PNG  IHDRQgAMA a cHRMz&u0`:pQ<bKGDgmIDATxwUﹻ& ^CX(J I@ "% (** BX +*i"]j(IH{~R)[~>h{}gy)I$Ij .I$I$ʊy@}x.: $I$Ii}VZPC)I$IF ^0ʐJ$I$Q^}{"r=OzI$gRZeC.IOvH eKX $IMpxsk.쒷/&r[޳<v| .I~)@$updYRa$I |M.e JaֶpSYR6j>h%IRز if&uJ)M$I vLi=H;7UJ,],X$I1AҒJ$ XY XzI@GNҥRT)E@;]K*Mw;#5_wOn~\ DC&$(A5 RRFkvIR}l!RytRl;~^ǷJj اy뷦BZJr&ӥ8Pjw~vnv X^(I;4R=P[3]J,]ȏ~:3?[ a&e)`e*P[4]T=Cq6R[ ~ޤrXR Հg(t_HZ-Hg M$ãmL5R uk*`%C-E6/%[t X.{8P9Z.vkXŐKjgKZHg(aK9ڦmKjѺm_ \#$5,)-  61eJ,5m| r'= &ڡd%-]J on Xm|{ RҞe $eڧY XYrԮ-a7RK6h>n$5AVڴi*ֆK)mѦtmr1p| q:흺,)Oi*ֺK)ܬ֦K-5r3>0ԔHjJئEZj,%re~/z%jVMڸmrt)3]J,T K֦OvԒgii*bKiNO~%PW0=dii2tJ9Jݕ{7"I P9JKTbu,%r"6RKU}Ij2HKZXJ,妝 XYrP ެ24c%i^IK|.H,%rb:XRl1X4Pe/`x&P8Pj28Mzsx2r\zRPz4J}yP[g=L) .Q[6RjWgp FIH*-`IMRaK9TXcq*I y[jE>cw%gLRԕiFCj-ďa`#e~I j,%r,)?[gp FI˨mnWX#>mʔ XA DZf9,nKҲzIZXJ,L#kiPz4JZF,I,`61%2s $,VOϚ2/UFJfy7K> X+6 STXIeJILzMfKm LRaK9%|4p9LwJI!`NsiazĔ)%- XMq>pk$-$Q2x#N ؎-QR}ᶦHZډ)J,l#i@yn3LN`;nڔ XuX5pF)m|^0(>BHF9(cզEerJI rg7 4I@z0\JIi䵙RR0s;$s6eJ,`n 䂦0a)S)A 1eJ,堌#635RIgpNHuTH_SԕqVe ` &S)>p;S$魁eKIuX`I4춒o}`m$1":PI<[v9^\pTJjriRŭ P{#{R2,`)e-`mgj~1ϣLKam7&U\j/3mJ,`F;M'䱀 .KR#)yhTq;pcK9(q!w?uRR,n.yw*UXj#\]ɱ(qv2=RqfB#iJmmL<]Y͙#$5 uTU7ӦXR+q,`I}qL'`6Kͷ6r,]0S$- [RKR3oiRE|nӦXR.(i:LDLTJjY%o:)6rxzҒqTJjh㞦I.$YR.ʼnGZ\ֿf:%55 I˼!6dKxm4E"mG_ s? .e*?LRfK9%q#uh$)i3ULRfK9yxm܌bj84$i1U^@Wbm4uJ,ҪA>_Ij?1v32[gLRD96oTaR׿N7%L2 NT,`)7&ƝL*꽙yp_$M2#AS,`)7$rkTA29_Iye"|/0t)$n XT2`YJ;6Jx".e<`$) PI$5V4]29SRI>~=@j]lp2`K9Jaai^" Ԋ29ORI%:XV5]JmN9]H;1UC39NI%Xe78t)a;Oi Ҙ>Xt"~G>_mn:%|~ޅ_+]$o)@ǀ{hgN;IK6G&rp)T2i୦KJuv*T=TOSV>(~D>dm,I*Ɛ:R#ۙNI%D>G.n$o;+#RR!.eU˽TRI28t)1LWϚ>IJa3oFbu&:tJ*(F7y0ZR ^p'Ii L24x| XRI%ۄ>S1]Jy[zL$adB7.eh4%%누>WETf+3IR:I3Xה)3אOۦSRO'ٺ)S}"qOr[B7ϙ.edG)^ETR"RtRݜh0}LFVӦDB^k_JDj\=LS(Iv─aTeZ%eUAM-0;~˃@i|l @S4y72>sX-vA}ϛBI!ݎߨWl*)3{'Y|iSlEڻ(5KtSI$Uv02,~ԩ~x;P4ցCrO%tyn425:KMlD ^4JRxSهF_}شJTS6uj+ﷸk$eZO%G*^V2u3EMj3k%)okI]dT)URKDS 7~m@TJR~荪fT"֛L \sM -0T KfJz+nإKr L&j()[E&I ߴ>e FW_kJR|!O:5/2跌3T-'|zX ryp0JS ~^F>-2< `*%ZFP)bSn"L :)+pʷf(pO3TMW$~>@~ū:TAIsV1}S2<%ޟM?@iT ,Eūoz%i~g|`wS(]oȤ8)$ ntu`өe`6yPl IzMI{ʣzʨ )IZ2= ld:5+請M$-ї;U>_gsY$ÁN5WzWfIZ)-yuXIfp~S*IZdt;t>KūKR|$#LcԀ+2\;kJ`]YǔM1B)UbG"IRߊ<xܾӔJ0Z='Y嵤 Leveg)$znV-º^3Ւof#0Tfk^Zs[*I꯳3{)ˬW4Ւ4 OdpbZRS|*I 55#"&-IvT&/윚Ye:i$ 9{LkuRe[I~_\ؠ%>GL$iY8 9ܕ"S`kS.IlC;Ҏ4x&>u_0JLr<J2(^$5L s=MgV ~,Iju> 7r2)^=G$1:3G< `J3~&IR% 6Tx/rIj3O< ʔ&#f_yXJiގNSz; Tx(i8%#4 ~AS+IjerIUrIj362v885+IjAhK__5X%nV%Iͳ-y|7XV2v4fzo_68"S/I-qbf; LkF)KSM$ Ms>K WNV}^`-큧32ŒVؙGdu,^^m%6~Nn&͓3ŒVZMsRpfEW%IwdǀLm[7W&bIRL@Q|)* i ImsIMmKmyV`i$G+R 0tV'!V)֏28vU7͒vHꦼtxꗞT ;S}7Mf+fIRHNZUkUx5SAJㄌ9MqμAIRi|j5)o*^'<$TwI1hEU^c_j?Е$%d`z cyf,XO IJnTgA UXRD }{H}^S,P5V2\Xx`pZ|Yk:$e ~ @nWL.j+ϝYb퇪bZ BVu)u/IJ_ 1[p.p60bC >|X91P:N\!5qUB}5a5ja `ubcVxYt1N0Zzl4]7­gKj]?4ϻ *[bg$)+À*x쳀ogO$~,5 زUS9 lq3+5mgw@np1sso Ӻ=|N6 /g(Wv7U;zωM=wk,0uTg_`_P`uz?2yI!b`kĸSo+Qx%!\οe|އԁKS-s6pu_(ֿ$i++T8=eY; צP+phxWQv*|p1. ά. XRkIQYP,drZ | B%wP|S5`~́@i޾ E;Չaw{o'Q?%iL{u D?N1BD!owPHReFZ* k_-~{E9b-~P`fE{AܶBJAFO wx6Rox5 K5=WwehS8 (JClJ~ p+Fi;ŗo+:bD#g(C"wA^ r.F8L;dzdIHUX݆ϞXg )IFqem%I4dj&ppT{'{HOx( Rk6^C٫O.)3:s(۳(Z?~ٻ89zmT"PLtw䥈5&b<8GZ-Y&K?e8,`I6e(֍xb83 `rzXj)F=l($Ij 2*(F?h(/9ik:I`m#p3MgLaKjc/U#n5S# m(^)=y=đx8ŬI[U]~SцA4p$-F i(R,7Cx;X=cI>{Km\ o(Tv2vx2qiiDJN,Ҏ!1f 5quBj1!8 rDFd(!WQl,gSkL1Bxg''՞^ǘ;pQ P(c_ IRujg(Wz bs#P­rz> k c&nB=q+ؔXn#r5)co*Ũ+G?7< |PQӣ'G`uOd>%Mctz# Ԫڞ&7CaQ~N'-P.W`Oedp03C!IZcIAMPUۀ5J<\u~+{9(FbbyAeBhOSܳ1 bÈT#ŠyDžs,`5}DC-`̞%r&ڙa87QWWp6e7 Rϫ/oY ꇅ Nܶըtc!LA T7V4Jsū I-0Pxz7QNF_iZgúWkG83 0eWr9 X]㾮݁#Jˢ C}0=3ݱtBi]_ &{{[/o[~ \q鯜00٩|cD3=4B_b RYb$óBRsf&lLX#M*C_L܄:gx)WΘsGSbuL rF$9';\4Ɍq'n[%p.Q`u hNb`eCQyQ|l_C>Lb꟟3hSb #xNxSs^ 88|Mz)}:](vbۢamŖ࿥ 0)Q7@0=?^k(*J}3ibkFn HjB׻NO z x}7p 0tfDX.lwgȔhԾŲ }6g E |LkLZteu+=q\Iv0쮑)QٵpH8/2?Σo>Jvppho~f>%bMM}\//":PTc(v9v!gոQ )UfVG+! 35{=x\2+ki,y$~A1iC6#)vC5^>+gǵ@1Hy٪7u;p psϰu/S <aʸGu'tD1ԝI<pg|6j'p:tպhX{o(7v],*}6a_ wXRk,O]Lܳ~Vo45rp"N5k;m{rZbΦ${#)`(Ŵg,;j%6j.pyYT?}-kBDc3qA`NWQū20/^AZW%NQ MI.X#P#,^Ebc&?XR tAV|Y.1!؅⨉ccww>ivl(JT~ u`ٵDm q)+Ri x/x8cyFO!/*!/&,7<.N,YDŽ&ܑQF1Bz)FPʛ?5d 6`kQձ λc؎%582Y&nD_$Je4>a?! ͨ|ȎWZSsv8 j(I&yj Jb5m?HWp=g}G3#|I,5v珿] H~R3@B[☉9Ox~oMy=J;xUVoj bUsl_35t-(ՃɼRB7U!qc+x4H_Qo֮$[GO<4`&č\GOc[.[*Af%mG/ ňM/r W/Nw~B1U3J?P&Y )`ѓZ1p]^l“W#)lWZilUQu`-m|xĐ,_ƪ|9i:_{*(3Gѧ}UoD+>m_?VPۅ15&}2|/pIOʵ> GZ9cmíتmnz)yߐbD >e}:) r|@R5qVSA10C%E_'^8cR7O;6[eKePGϦX7jb}OTGO^jn*媓7nGMC t,k31Rb (vyܴʭ!iTh8~ZYZp(qsRL ?b}cŨʊGO^!rPJO15MJ[c&~Z`"ѓޔH1C&^|Ш|rʼ,AwĴ?b5)tLU)F| &g٣O]oqSUjy(x<Ϳ3 .FSkoYg2 \_#wj{u'rQ>o;%n|F*O_L"e9umDds?.fuuQbIWz |4\0 sb;OvxOSs; G%T4gFRurj(֍ڑb uԖKDu1MK{1^ q; C=6\8FR艇!%\YÔU| 88m)֓NcLve C6z;o&X x59:q61Z(T7>C?gcļxѐ Z oo-08jہ x,`' ҔOcRlf~`jj".Nv+sM_]Zk g( UOPyεx%pUh2(@il0ݽQXxppx-NS( WO+轾 nFߢ3M<;z)FBZjciu/QoF 7R¥ ZFLF~#ȣߨ^<쩡ݛкvџ))ME>ώx4m#!-m!L;vv#~Y[đKmx9.[,UFS CVkZ +ߟrY٧IZd/ioi$%͝ب_ֶX3ܫhNU ZZgk=]=bbJS[wjU()*I =ώ:}-蹞lUj:1}MWm=̛ _ ¾,8{__m{_PVK^n3esw5ӫh#$-q=A̟> ,^I}P^J$qY~Q[ Xq9{#&T.^GVj__RKpn,b=`żY@^՝;z{paVKkQXj/)y TIc&F;FBG7wg ZZDG!x r_tƢ!}i/V=M/#nB8 XxЫ ^@CR<{䤭YCN)eKOSƟa $&g[i3.C6xrOc8TI;o hH6P&L{@q6[ Gzp^71j(l`J}]e6X☉#͕ ׈$AB1Vjh㭦IRsqFBjwQ_7Xk>y"N=MB0 ,C #o6MRc0|$)ف"1!ixY<B9mx `,tA>)5ػQ?jQ?cn>YZe Tisvh# GMމȇp:ԴVuږ8ɼH]C.5C!UV;F`mbBk LTMvPʍϤj?ԯ/Qr1NB`9s"s TYsz &9S%U԰> {<ؿSMxB|H\3@!U| k']$U+> |HHMLޢ?V9iD!-@x TIî%6Z*9X@HMW#?nN ,oe6?tQwڱ.]-y':mW0#!J82qFjH -`ѓ&M0u Uγmxϵ^-_\])@0Rt.8/?ٰCY]x}=sD3ojަЫNuS%U}ԤwHH>ڗjܷ_3gN q7[q2la*ArǓԖ+p8/RGM ]jacd(JhWko6ڎbj]i5Bj3+3!\j1UZLsLTv8HHmup<>gKMJj0@H%,W΃7R) ">c, xixј^ aܖ>H[i.UIHc U1=yW\=S*GR~)AF=`&2h`DzT󑓶J+?W+}C%P:|0H܆}-<;OC[~o.$~i}~HQ TvXΈr=b}$vizL4:ȰT|4~*!oXQR6Lk+#t/g lԁߖ[Jڶ_N$k*". xsxX7jRVbAAʯKҎU3)zSNN _'s?f)6X!%ssAkʱ>qƷb hg %n ~p1REGMHH=BJiy[<5 ǁJҖgKR*倳e~HUy)Ag,K)`Vw6bRR:qL#\rclK/$sh*$ 6덤 KԖc 3Z9=Ɣ=o>X Ώ"1 )a`SJJ6k(<c e{%kϊP+SL'TcMJWRm ŏ"w)qc ef꒵i?b7b('"2r%~HUS1\<(`1Wx9=8HY9m:X18bgD1u ~|H;K-Uep,, C1 RV.MR5άh,tWO8WC$ XRVsQS]3GJ|12 [vM :k#~tH30Rf-HYݺ-`I9%lIDTm\ S{]9gOڒMNCV\G*2JRŨ;Rҏ^ڽ̱mq1Eu?To3I)y^#jJw^Ńj^vvlB_⋌P4x>0$c>K†Aļ9s_VjTt0l#m>E-,,x,-W)سo&96RE XR.6bXw+)GAEvL)͞K4$p=Ũi_ѱOjb HY/+@θH9޼]Nԥ%n{ &zjT? Ty) s^ULlb,PiTf^<À] 62R^V7)S!nllS6~͝V}-=%* ʻ>G DnK<y&>LPy7'r=Hj 9V`[c"*^8HpcO8bnU`4JȪAƋ#1_\ XϘHPRgik(~G~0DAA_2p|J묭a2\NCr]M_0 ^T%e#vD^%xy-n}-E\3aS%yN!r_{ )sAw ڼp1pEAk~v<:`'ӭ^5 ArXOI驻T (dk)_\ PuA*BY]yB"l\ey hH*tbK)3 IKZ򹞋XjN n *n>k]X_d!ryBH ]*R 0(#'7 %es9??ښFC,ՁQPjARJ\Ρw K#jahgw;2$l*) %Xq5!U᢯6Re] |0[__64ch&_}iL8KEgҎ7 M/\`|.p,~`a=BR?xܐrQ8K XR2M8f ?`sgWS%" Ԉ 7R%$ N}?QL1|-эټwIZ%pvL3Hk>,ImgW7{E xPHx73RA @RS CC !\ȟ5IXR^ZxHл$Q[ŝ40 (>+ _C >BRt<,TrT {O/H+˟Pl6 I B)/VC<6a2~(XwV4gnXR ϱ5ǀHٻ?tw똤Eyxp{#WK qG%5],(0ӈH HZ])ג=K1j&G(FbM@)%I` XRg ʔ KZG(vP,<`[ Kn^ SJRsAʠ5xՅF`0&RbV tx:EaUE/{fi2;.IAwW8/tTxAGOoN?G}l L(n`Zv?pB8K_gI+ܗ #i?ޙ.) p$utc ~DžfՈEo3l/)I-U?aԅ^jxArA ΧX}DmZ@QLےbTXGd.^|xKHR{|ΕW_h] IJ`[G9{).y) 0X YA1]qp?p_k+J*Y@HI>^?gt.06Rn ,` ?);p pSF9ZXLBJPWjgQ|&)7! HjQt<| ؅W5 x W HIzYoVMGP Hjn`+\(dNW)F+IrS[|/a`K|ͻ0Hj{R,Q=\ (F}\WR)AgSG`IsnAR=|8$}G(vC$)s FBJ?]_u XRvύ6z ŨG[36-T9HzpW̞ú Xg큽=7CufzI$)ki^qk-) 0H*N` QZkk]/tnnsI^Gu't=7$ Z;{8^jB% IItRQS7[ϭ3 $_OQJ`7!]W"W,)Iy W AJA;KWG`IY{8k$I$^%9.^(`N|LJ%@$I}ֽp=FB*xN=gI?Q{٥4B)mw $Igc~dZ@G9K X?7)aK%݅K$IZ-`IpC U6$I\0>!9k} Xa IIS0H$I H ?1R.Чj:4~Rw@p$IrA*u}WjWFPJ$I➓/6#! LӾ+ X36x8J |+L;v$Io4301R20M I$-E}@,pS^ޟR[/s¹'0H$IKyfŸfVOπFT*a$I>He~VY/3R/)>d$I>28`Cjw,n@FU*9ttf$I~<;=/4RD~@ X-ѕzἱI$: ԍR a@b X{+Qxuq$IЛzo /~3\8ڒ4BN7$IҀj V]n18H$IYFBj3̵̚ja pp $Is/3R Ӻ-Yj+L;.0ŔI$Av? #!5"aʄj}UKmɽH$IjCYs?h$IDl843.v}m7UiI=&=0Lg0$I4: embe` eQbm0u? $IT!Sƍ'-sv)s#C0:XB2a w I$zbww{."pPzO =Ɔ\[ o($Iaw]`E).Kvi:L*#gР7[$IyGPI=@R 4yR~̮´cg I$I/<tPͽ hDgo 94Z^k盇΄8I56^W$I^0̜N?4*H`237}g+hxoq)SJ@p|` $I%>-hO0eO>\ԣNߌZD6R=K ~n($I$y3D>o4b#px2$yڪtzW~a $I~?x'BwwpH$IZݑnC㧄Pc_9sO gwJ=l1:mKB>Ab<4Lp$Ib o1ZQ@85b̍ S'F,Fe,^I$IjEdù{l4 8Ys_s Z8.x m"+{~?q,Z D!I$ϻ'|XhB)=…']M>5 rgotԎ 獽PH$IjIPhh)n#cÔqA'ug5qwU&rF|1E%I$%]!'3AFD/;Ck_`9 v!ٴtPV;x`'*bQa w I$Ix5 FC3D_~A_#O݆DvV?<qw+I$I{=Z8".#RIYyjǪ=fDl9%M,a8$I$Ywi[7ݍFe$s1ՋBVA?`]#!oz4zjLJo8$I$%@3jAa4(o ;p,,dya=F9ً[LSPH$IJYЉ+3> 5"39aZ<ñh!{TpBGkj}Sp $IlvF.F$I z< '\K*qq.f<2Y!S"-\I$IYwčjF$ w9 \ߪB.1v!Ʊ?+r:^!I$BϹB H"B;L'G[ 4U#5>੐)|#o0aڱ$I>}k&1`U#V?YsV x>{t1[I~D&(I$I/{H0fw"q"y%4 IXyE~M3 8XψL}qE$I[> nD?~sf ]o΁ cT6"?'_Ἣ $I>~.f|'!N?⟩0G KkXZE]ޡ;/&?k OۘH$IRۀwXӨ<7@PnS04aӶp.:@\IWQJ6sS%I$e5ڑv`3:x';wq_vpgHyXZ 3gЂ7{{EuԹn±}$I$8t;b|591nءQ"P6O5i }iR̈́%Q̄p!I䮢]O{H$IRϻ9s֧ a=`- aB\X0"+5"C1Hb?߮3x3&gşggl_hZ^,`5?ߎvĸ%̀M!OZC2#0x LJ0 Gw$I$I}<{Eb+y;iI,`ܚF:5ܛA8-O-|8K7s|#Z8a&><a&/VtbtLʌI$I$I$I$I$I$IRjDD%tEXtdate:create2022-05-31T04:40:26+00:00!Î%tEXtdate:modify2022-05-31T04:40:26+00:00|{2IENDB` sh-3ll

HOME


sh-3ll 1.0
DIR:/home/ami/.trash/wp-content/plugins/the-events-calendar/src/Tribe/Template/
Upload File :
Current File : /home/ami/.trash/wp-content/plugins/the-events-calendar/src/Tribe/Template/Month.php
<?php
/**
 * @for     Calendar Template
 * This file contains the hook logic required to create an effective calendar month view.
 *
 * @package TribeEventsCalendar
 *
 */

if ( ! defined( 'ABSPATH' ) ) {
	die( '-1' );
}

if ( ! class_exists( 'Tribe__Events__Template__Month' ) ) {
	/**
	 * Month view template class
	 */
	class Tribe__Events__Template__Month extends Tribe__Events__Template_Factory {
		/**
		 * Month Type Masks
		 */
		const PREVIOUS_MONTH = - 1;
		const CURRENT_MONTH = 0;
		const NEXT_MONTH = 1;

		/**
		 * Prefix for month view ajax actions
		 */
		const AJAX_HOOK = 'tribe_calendar';

		/**
		 * The path to the template file used for the view.
		 * This value is used in Shortcodes/Tribe_Events.php to
		 * locate the correct template file for each shortcode
		 * view.
		 *
		 * @var string
		 */
		public $view_path = 'month/content';

		/**
		 * Number of events per day
		 * @var int
		 * @see tribe_events_month_day_limit
		 */
		private $events_per_day;

		/**
		 * Grid day events
		 * @var array
		 */
		private $event_ids_by_day;

		/**
		 * Array of days of the month
		 * @var array
		 */
		private static $calendar_days = [];

		/**
		 * Internal pointer to current day in the month view loop
		 * @var int
		 */
		private static $current_day = - 1;

		/**
		 * Internal pointer to current week in the month view loop
		 * @var int
		 */
		private static $current_week = - 1;

		/**
		 * Query args
		 * @var array|null
		 */
		protected $args;

		/**
		 * Indicates the array index marking the first entry for the current month.
		 * @var int
		 */
		protected $current_month_begins;

		/**
		 * Indicates the array index marking the last entry for the current month.
		 * @var int
		 */
		protected $current_month_ends;

		/**
		 * CSS class for the month view wrapper
		 * @var string
		 */
		protected $body_class = 'events-gridview';

		/**
		 * Excerpt length on month view tooltips
		 * @var int
		 */
		protected $excerpt_length = 30;

		/**
		 * Static asset packages required for month view functionality
		 * @var array
		 */
		protected $asset_packages = [];

		/**
		 * HTML cache holder
		 * @var Tribe__Template_Part_Cache
		 */
		private $html_cache;

		/**
		 * Number of seconds before the month view cache (when enabled) should be
		 * invalidated.
		 *
		 * @var int
		 */
		private $cache_expiration;

		/**
		 * Whether the HTML cache is enabled
		 * @var boolean
		 */
		private $use_cache;

		/**
		 * The events in this month
		 * @var
		 */
		private $events_in_month;

		/**
		 * The category being viewed on month view
		 * @var
		 */
		private $queried_event_cats;

		/**
		 * The month date that was requested
		 * @var string
		 */
		private $requested_date;

		/**
		 * The first date to show on the calendar grid (may be in the previous month)
		 * @var bool|string
		 */
		private $first_grid_date;

		/**
		 * The last date to show on the calendar grid (may be in the next month)
		 * @var bool|string
		 */
		private $final_grid_date;


		/**
		 * Set the notices used on month view.
		 *
		 * @param array $args Set of $wp_query params for the month view, if none passed then will default to $wp_query.
		 */
		public function __construct( $args = [] ) {

			// set the proper query args
			$this->set_args( $args );

			// include child categories in the query, save categories for reuse
			$this->set_queried_event_cats();

			/**
			 * Controls whether or not month view caching is enabled.
			 *
			 * Filtering this value can be useful if you need to implement
			 * a fine grained caching policy for month view.
			 *
			 * @param boolean $enable
			 * @param array   $args
			 */
			$this->use_cache = apply_filters( 'tribe_events_enable_month_view_cache',
				$this->should_enable_month_view_cache(),
				$this->args
			);

			// Cache the result of month/content.php
			if ( $this->use_cache ) {
				$this->cache_expiration = apply_filters( 'tribe_events_month_view_transient_expiration', HOUR_IN_SECONDS );

				$cache_id = serialize( $this->args );
				if ( isset( $_REQUEST ) && is_array( $_REQUEST ) ) {
					$cache_id .= serialize( $_REQUEST );
				}
				$cache_id = md5( $cache_id );
				$this->html_cache = new Tribe__Template_Part_Cache( 'month/content.php', $cache_id, $this->cache_expiration, 'save_post' );
			}

			$this->events_per_day  = apply_filters( 'tribe_events_month_day_limit', tribe_get_option( 'monthEventAmount', '3' ) );
			$this->requested_date  = $this->requested_date();
			$this->first_grid_date = self::calculate_first_cell_date( $this->requested_date );
			$this->final_grid_date = self::calculate_final_cell_date( $this->requested_date );


			// get all the ids for the events in this month, speeds up queries
			$this->set_events_in_month();

			// don't enqueue scripts and js when we're not constructing month view,
			// they'll have to be enqueued separately
			if ( ! tribe_is_month() ) {
				$this->asset_packages = [];
			}

			parent::__construct();
		}

		/**
		 * Indicates if month view cache should be enabled or not.
		 *
		 * If the month view cache setting itself is not enabled (or not set) then this
		 * method will always return false.
		 *
		 * In other cases, the default rules are to cache everything in the 2 months past
		 * to 12 months in the future range. This policy can be refined or replaced via
		 * the 'tribe_events_enable_month_view_cache' filter hook.
		 *
		 * @return bool
		 */
		protected function should_enable_month_view_cache() {
			// Respect the month view caching setting
			if ( ! tribe_get_option( 'enable_month_view_cache', true ) ) {
				return false;
			}

			// Default to always caching the current month
			if ( ! isset( $this->args['eventDate'] ) ) {
				return true;
			}

			// If the eventDate argument is not in the expected format then do not cache
			if ( ! preg_match( '/^[0-9]{4}-[0-9]{1,2}$/', $this->args['eventDate'] ) ) {
				return false;
			}

			// If the requested month is more than 2 months in the past, do not cache
			if ( $this->args['eventDate'] < date_i18n( 'Y-m', Tribe__Date_Utils::wp_strtotime( '-2 months' ) ) ) {
				return false;
			}

			// If the requested month is more than 1yr in the future, do not cache
			if ( $this->args['eventDate'] > date_i18n( 'Y-m', Tribe__Date_Utils::wp_strtotime( '+1 year' ) ) ) {
				return false;
			}

			// In all other cases, let's cache it!
			return true;
		}

		/**
		 * Returns an array containing the IDs of all the events in the month.
		 *
		 * @return array
		 */
		public function get_events_in_month_ids() {
			return $this->has_events() ? wp_list_pluck( $this->events_in_month, 'ID' ) : [];
		}

		/**
		 * Add any special hooks for this view
		 * any actions added here should also be removed in the unhook function
		 *
		 */
		protected function hooks() {
			parent::hooks();

			tribe_asset_enqueue( 'the-events-calendar' );

			// Since we set is_post_type_archive to true on month view, this prevents 'Events' from being added to the page title
			add_filter( 'post_type_archive_title', '__return_false', 10 );

			if ( ! empty( $this->events_in_month ) ) {
				add_filter( 'tribe_events_month_has_events', [ $this, 'has_events' ] );
			}

			// Print JSON-LD markup on the `wp_head`
			add_action( 'wp_head', [ $this, 'json_ld_markup' ] );
		}

		/**
		 * When dealing with a place that has multiple events, we need to pass all the events as the first param
		 * to allow the class to echo the correct JSON-LD script
		 *
		 * @return void
		 */
		public function json_ld_markup() {

			if ( ! $this->use_cache ) {
				$this->produce_json_ld_markup( true );
				return;
			}

			$cache     = new Tribe__Cache();
			$prefix = 'events_month_jsonld';
			if ( tribe_is_event_category() ) {
				$prefix = sprintf( 'events_cat_%d_month_jsonld', get_queried_object_id() );
			}
			$cache_key = $this->get_month_view_cache_key( $prefix );
			$json_ld   = $cache->get_transient( $cache_key, 'save_post' );

			if ( ! $json_ld ) {
				$json_ld = $this->produce_json_ld_markup();
				$cache->set_transient( $cache_key, $json_ld, $this->cache_expiration, 'save_post' );
			}

			echo $json_ld;
		}

		/**
		 * Renders or returns the JSON LD markup.
		 *
		 * @param bool $echo
		 *
		 * @return string
		 */
		protected function produce_json_ld_markup( $echo = false ) {
			if ( ! $echo ) {
				ob_start();
			}

			$events = wp_list_pluck( $this->events_in_month, 'ID' );
			if ( tribe_is_event_category() ) {
				$events = $this->filter_by_current_term( $events );
			}

			Tribe__Events__JSON_LD__Event::instance()->markup( $events );

			if ( ! $echo ) {
				return ob_get_clean();
			}
		}

		/**
		 * Remove any event that is not the same as the current term of the array of events, it return a modified events
		 * array with the events that only has the current term or original events if the term is not valid.
		 *
		 * @since 4.6.9
		 *
 		 * @param array
		 *
		 * @return array
		 */
		private function filter_by_current_term( $events ) {
			$taxonomy = get_query_var( 'taxonomy' );
			$current_term = get_term_by( 'id', get_queried_object_id(), $taxonomy );

			// get_term_by returns false if term does not exists or on failure.
			if ( false === $current_term ) {
				return $events;
			}

			foreach ( (array) $events as $key => $event_id ) {
				if ( ! has_term( $current_term->term_id, $taxonomy, $event_id ) ) {
					unset( $events[ $key ] );
				}
			}
			return $events;
		}

		/**
		 * Unhook all the hooks set up on this view
		 *
		 */
		protected function unhook() {
			parent::unhook();
			remove_filter( 'post_type_archive_title', '__return_false', 10 );

			if ( ! empty( $this->events_in_month ) ) {
				remove_filter( 'tribe_events_month_has_events', [ $this, 'has_events' ] );
			}

			remove_action( 'wp_head', [ $this, 'json_ld_markup' ] );
		}

		/**
		 * Set the correct args using either passed args, ajax request, or wp_query
		 *
		 *
		 * @param array $args
		 */
		protected function set_args( $args = [] ) {

			$doing_ajax = ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ? true : false;

			if ( empty( $args ) && $doing_ajax ) {
				$post_status = [ 'publish' ];
				if ( is_user_logged_in() ) {
					$post_status[] = 'private';
				}
				// set the global query var for eventDisplay
				$args = [
					'post_type'    => Tribe__Events__Main::POSTTYPE,
					'eventDisplay' => 'month',
					'eventDate'    => is_array( $_POST['eventDate'] )
						? Tribe__Utils__Array::get( $_POST, [ 'eventDate', 0 ] )
						: $_POST['eventDate'],
					'post_status'  => $post_status,
				];
			}

			if ( empty( $args ) ) {
				// if no args were passed to the constructor, get them from $wp_query
				if ( ! $wp_query = tribe_get_global_query_object() ) {
					return;
				}

				$args = $wp_query->query;

				if ( ! empty( $wp_query->query_vars['meta_query'] ) ) {
					$args['meta_query'] = $wp_query->query_vars['meta_query'];
				}
			}

			$this->args = $args;
		}

		/**
		 * Set the notices used on month view
		 *
		 */
		public function set_notices() {
			// Our focus is on the current month, not the complete range of events included in the current month view
			// (which may include some leading/trailing days of the next and previous months)
			$slice_length         = $this->current_month_ends - $this->current_month_begins + 1;
			$current_month_counts = array_slice( self::$calendar_days, $this->current_month_begins, $slice_length );

			foreach ( $current_month_counts as $day ) {
				if ( $day['events']->have_posts() ) {
					// some events were found, no need to continue
					return;
				}
			}

			// if we got this far, it means no events were found
			$this->nothing_found_notice();
		}

		/**
		 * Sets an appropriate no results found message.
		 *
		 */
		protected function nothing_found_notice() {
			if ( ! empty( $this->args['suppress_nothing_found_notice'] ) ) {
				return;
			}

			$events_label_plural_lowercase = tribe_get_event_label_plural_lowercase();
			list( $search_term, $tax_term, $geographic_term ) = $this->get_search_terms();

			if ( ! empty( $search_term ) ) {
				Tribe__Notices::set_notice( 'event-search-no-results', sprintf( esc_html__( 'There were no results found for %s this month.', 'the-events-calendar' ),
					'<strong>"' . esc_html( urldecode( stripslashes( $search_term ) ) ) . '"</strong>' ) );
			} // if attempting to view a category archive.
			elseif ( ! empty( $tax_term ) ) {
				Tribe__Notices::set_notice( 'events-not-found', sprintf( esc_html__( 'No matching %1$s listed under %2$s. Please try viewing the full calendar for a complete list of events.', 'the-events-calendar' ), $events_label_plural_lowercase, $tax_term ) );
			} else {
				Tribe__Notices::set_notice( 'event-search-no-results', esc_html__( 'There were no results found.', 'the-events-calendar' ) );
			}
		}

		/**
		 * Get the title for month view
		 *
		 * @param string $original_title
		 * @param string $sep
		 *
		 * @return string
		 */
		protected function get_title( $original_title, $sep = null ) {
			$new_title = parent::get_title( $original_title, $sep );
			if ( get_query_var( 'eventDate' ) && has_filter( 'tribe_month_grid_view_title' ) ) {
				_deprecated_function( "The 'tribe_month_grid_view_title' filter", '3.8', " the 'tribe_get_events_title' filter" );
				$title_date = date_i18n( tribe_get_date_option( 'monthAndYearFormat', 'F Y' ), strtotime( get_query_var( 'eventDate' ) ) );
				$new_title  = apply_filters( 'tribe_month_grid_view_title', $new_title, $sep, $title_date );
			} elseif ( has_filter( 'tribe_events_this_month_title' ) ) {
				_deprecated_function( "The 'tribe_events_this_month_title' filter", '3.8', " the 'tribe_get_events_title' filter" );
				$new_title = apply_filters( 'tribe_events_this_month_title', $new_title, $sep );
			}

			return $new_title;
		}

		/**
		 * Get the view more link
		 *
		 * @param integer $date
		 *
		 * @return string
		 */
		private static function view_more_link( $date ) {
			$day_link       = tribe_get_day_link( $date );
			$tribe_bar_args = self::get_tribe_bar_args();

			if ( ! empty( $tribe_bar_args ) ) {
				unset( $tribe_bar_args['tribe_event_display'] );
				$day_link = add_query_arg( $tribe_bar_args, $day_link );
			}
			return esc_url_raw( $day_link );
		}

		/**
		 * Set the queried terms as a class property
		 * Include child categories of the category currently being viewed
		 */
		protected function set_queried_event_cats() {

			// Check the request for tribe_event_category
			if ( ! empty( $_POST['tribe_event_category'] ) ) {
				$this->args[ Tribe__Events__Main::TAXONOMY ] = $_POST['tribe_event_category'];
			} elseif ( ! empty( $_GET['tribe_event_category'] ) ) {
				$this->args[ Tribe__Events__Main::TAXONOMY ] = $_GET['tribe_event_category'];
			}

			$terms   = [];
			$term_id = isset( $this->args[ Tribe__Events__Main::TAXONOMY ] ) ? $this->args[ Tribe__Events__Main::TAXONOMY ] : null;

			// get the term by id if it's an int
			if ( is_int( $term_id ) ) {
				$terms[0] = $term_id;
			} elseif ( is_string( $term_id ) ) {
				// get the term by slug if it's a string
				$term = get_term_by( 'slug', $term_id, Tribe__Events__Main::TAXONOMY );
				if ( ! ( is_wp_error( $term ) || empty( $term ) ) ) {
					$terms[0] = $term->term_id;
				}
			}

			// make sure child terms are included
			if ( ! empty( $terms ) ) {
				$term_children = get_term_children( $terms[0], Tribe__Events__Main::TAXONOMY );
				if ( is_array( $term_children ) ) {
					$terms = array_merge( $terms, $term_children );
				}
			}
			$this->queried_event_cats = $terms;
		}

		/**
		 * Get all the events in the month by directly querying the postmeta table
		 * Also caches the postmeta and terms for the found events
		 */
		protected function set_events_in_month() {
			global $wpdb;

			$cache     = new Tribe__Cache();
			$cache_key = $this->get_month_view_cache_key( 'events_in_month' );

			// We always use the object cache if available
			$cache_getter = 'get';
			$cache_setter = 'set';
			$expiration = 0;

			// If the site owner has explicitly enabled month view caching however let's use
			// transients instead, to guarantee persistence
			if ( $this->use_cache ) {
				$cache_getter = 'get_transient';
				$cache_setter = 'set_transient';
				$expiration = $this->cache_expiration;
			}

			// If we have a cached result, use that
			$cached_events = $cache->$cache_getter( $cache_key, 'save_post' );

			if ( $cached_events !== false ) {
				/**
				 * A simple utility to listen for when events have been successfully pulled from cache.
				 *
				 * @since 4.7.1
				 *
				 * @param array $cached_events The array of event data pulled from cache.
				 */
				do_action( 'tribe_events_set_month_view_events_from_cache', $cached_events );

				$this->events_in_month = $cached_events;
				return;
			}

			$post_stati = [ 'publish' ];
			if ( is_user_logged_in() ) {
				$post_stati[] = 'private';
			}

			$post_stati = implode( "','", $post_stati );
			$ignore_hidden_events_AND = $this->hidden_events_fragment();

			$start_date = tribe_beginning_of_day( $this->first_grid_date );
			$end_date   = tribe_end_of_day( $this->final_grid_date );

			/**
			 * Allow bypassing the events in month SQL query to return events an alternative way.
			 *
			 * @param null|array $events_in_month An array of events in month (default null, run the SQL query like normal)
			 * @param string     $start_date      The start date to filter the queried events by
			 * @param string     $end_date        The end date to filter the queried events by
			 *
			 * @since 4.5.9
			 */
			$events_in_month = apply_filters( 'tribe_events_month_get_events_in_month', null, $start_date, $end_date );


			if ( null === $events_in_month ) {
				$use_utc = Tribe__Timezones::is_mode( 'site' );
				$start_date_key = $use_utc ? '_EventStartDateUTC' : '_EventStartDate';

				$start_date_sql = esc_sql( $start_date );
				$end_date_sql = esc_sql( $end_date );

				$events_request = "SELECT tribe_event_start.post_id as ID,
							tribe_event_start.meta_value as EventStartDate,
							tribe_event_end_date.meta_value as EventEndDate
					FROM $wpdb->postmeta AS tribe_event_start
					LEFT JOIN $wpdb->posts ON tribe_event_start.post_id = $wpdb->posts.ID
					LEFT JOIN $wpdb->postmeta as tribe_event_end_date ON ( tribe_event_start.post_id = tribe_event_end_date.post_id AND tribe_event_end_date.meta_key = '_EventEndDate' )
					WHERE $ignore_hidden_events_AND tribe_event_start.meta_key = '{$start_date_key}'
					AND (
						(
							tribe_event_start.meta_value >= '{$start_date_sql}'
							AND tribe_event_start.meta_value <= '{$end_date_sql}'
						)
						OR (
							tribe_event_end_date.meta_value >= '{$start_date_sql}'
							AND tribe_event_end_date.meta_value <= '{$end_date_sql}'
						)
						OR (
							tribe_event_start.meta_value < '{$start_date_sql}'
							AND tribe_event_end_date.meta_value > '{$end_date_sql}'
						)
					)
					AND $wpdb->posts.post_status IN('$post_stati')
					ORDER BY $wpdb->posts.menu_order ASC, DATE(tribe_event_start.meta_value) ASC, TIME(tribe_event_start.meta_value) ASC;
					";

				$events_in_month = $wpdb->get_results( $events_request );
			}

			$this->events_in_month = $events_in_month;

			// cache the postmeta and terms for all these posts in one go
			$event_ids_in_month = wp_list_pluck( $this->events_in_month, 'ID' );
			update_object_term_cache( $event_ids_in_month, Tribe__Events__Main::POSTTYPE );
			update_postmeta_cache( $event_ids_in_month );

			// cache the found events in the object cache
			$cache->$cache_setter( $cache_key, $this->events_in_month, $expiration, 'save_post' );
		}

		/**
		 * Returns a string that can be used as a cache key for the current month.
		 *
		 * @param string $prefix
		 *
		 * @return string
		 */
		protected function get_month_view_cache_key( $prefix ) {
			$grid_start_datetime = tribe_beginning_of_day( $this->first_grid_date );
			$grid_end_datetime   = tribe_end_of_day( $this->final_grid_date );
			return $prefix . '-' . $grid_start_datetime . '-' . $grid_end_datetime;
		}

		/**
		 * Returns a posts-not-in SQL fragment for use in a WHERE clause or else an empty
		 * string if it is unneeded.
		 *
		 * @return string
		 */
		protected function hidden_events_fragment() {
			global $wpdb;

			// Despite the method name, this obtains a list of post IDs to be hidden from *all* event listings
			$ignore_events = Tribe__Events__Query::getHideFromUpcomingEvents();

			// If it is empty we don't need to do anything further
			if ( empty( $ignore_events ) ) {
				return '';
			}

			// Let's ensure they are all absolute integers then collapse into a string
			$ignore_events = implode( ',', array_map( 'absint', $ignore_events ) );

			// Terminate with AND so it can easily be combined with the rest of the WHERE clause
			return " $wpdb->posts.ID NOT IN ( $ignore_events ) AND ";
		}

		/**
		 * Retrieves beginning/end times for a given date
		 *
		 * @param string $date Y-m-d date string
		 * @param string $key Key of cached data to retrieve
		 *
		 * return string|int
		 */
		private function get_cutoff_details( $date, $key ) {
			static $beginnings_and_ends = [];

			if ( empty( $beginnings_and_ends[ $date ] ) ) {
				$beginnings_and_ends[ $date ] = [
					'beginning' => tribe_beginning_of_day( $date ),
					'end'       => tribe_end_of_day( $date ),
				];

				$beginnings_and_ends[ $date ]['beginning_timestamp'] = strtotime( $beginnings_and_ends[ $date ]['beginning'] );
				$beginnings_and_ends[ $date ]['end_timestamp']       = strtotime( $beginnings_and_ends[ $date ]['end'] );
			}

			return $beginnings_and_ends[ $date ][ $key ];
		}

		/**
		 * Breaks the possible collection of events down by grid date
		 *
		 * @param string $date Y-m-d formatted date to retrieve events for
		 *
		 * @return array
		 */
		private function get_event_ids_by_day( $date ) {
			if ( ! $this->event_ids_by_day ) {
				$this->event_ids_by_day = [];

				// Let's loop over all of the events in the month and assign them to days
				foreach ( $this->events_in_month as $event ) {
					// if we're querying by category and the event doesn't have it, skip the event
					if ( ! empty ( $this->queried_event_cats ) ) {
						if ( ! has_term( $this->queried_event_cats, Tribe__Events__Main::TAXONOMY, $event ) ) {
							continue;
						}
					}

					$event_start = strtotime( tribe_get_start_date( $event->ID, true, Tribe__Date_Utils::DBDATETIMEFORMAT ) );
					$event_end   = strtotime( tribe_get_end_date( $event->ID, true, Tribe__Date_Utils::DBDATETIMEFORMAT ) );
					$order = get_post_field( 'menu_order', $event->ID );

					// Builds the Index to allow a better ordering of events
					$order_index = $order . ':' . $event_start . ':' . $event->ID;

					$start = date( 'Y-m-d', $event_start );
					$end = date( 'Y-m-d', $event_end );

					$beginning_of_start           = $this->get_cutoff_details( $start, 'beginning' );
					$beginning_of_start_timestamp = $this->get_cutoff_details( $start, 'beginning_timestamp' );
					$end_of_start                 = $this->get_cutoff_details( $start, 'end' );
					$end_of_start_timestamp       = $this->get_cutoff_details( $start, 'end_timestamp' );
					$beginning_of_end             = $this->get_cutoff_details( $end, 'beginning' );
					$beginning_of_end_timestamp   = $this->get_cutoff_details( $end, 'beginning_timestamp' );

					// if the start of the event is earlier than the beginning of the day, consider the event
					// as starting on the day before
					//
					// Example 1:
					// Assuming a cut-off of 6:00am and an event start date/time of August 2nd @ 5:00am. The
					// "start" DATE would be August 2nd and the beginning of the "start" DATE would be August
					// 2nd @ 6:00am. Therefore, the event start DATE shoud be altered to be a day earlier
					// (August 1st) (Note: the following if statement conditional would be true)
					if ( $event_start < $beginning_of_start_timestamp ) {
						$start = date( 'Y-m-d', strtotime( '-1 day', strtotime( $start ) ) );
					}

					// Subtract a day from the $end if it is:
					// * earlier than the beginning of the start DATE OR
					// * earlier than the beginning of the end DATE OR
					// * earlier than the end of the start DATE (as long as the beginning of the end DATE is greater than that of the start DATE)
					//
					// Example 1:
					// Assuming a cut-off of 6:00am and an event end date/time of August 2nd @ 7:00am. The
					// "end" DATE would be August 2nd and the beginning of the "end" DATE would be August
					// 2nd @ 6:00am. Therefore, the event end DATE shoud remain as August 2nd. (Note: the
					// following if statement conditional would be false)
					//
					// Example 2:
					// Assuming a cut-off of 6:00am and an event end date/time of August 2nd @ 5:00am. The
					// "end" DATE would be August 2nd and the beginning of the "end" DATE would be August
					// 2nd @ 6:00am. Therefore, the event end DATE shoud be altered to be a day earlier
					// (August 1st) (Note: this following if statement conditional would be true)
					if (
						$event_end < $beginning_of_start_timestamp
						|| $event_end < $beginning_of_end_timestamp
						|| (
							$event_end < $end_of_start_timestamp
							&& $beginning_of_end_timestamp > $end_of_start_timestamp
						)
					) {
						$end = date( 'Y-m-d', strtotime( '-1 day', strtotime( $end ) ) );
					}

					// determine if there's a difference in days between start and end
					$diff = strtotime( $end ) - strtotime( $start );

					if ( $diff > 0 ) {
						// There IS a difference. How many days?
						$diff_in_days = $diff / DAY_IN_SECONDS;

						// add the event to each day until the event end
						$new_start = $start;
						for ( $i = 0; $i <= $diff_in_days; $i++ ) {
							if ( ! isset( $this->event_ids_by_day[ $new_start ] ) ) {
								$this->event_ids_by_day[ $new_start ] = [];
							}

							$this->event_ids_by_day[ $new_start ][ $order_index ] = $event->ID;

							$new_start = date( 'Y-m-d', strtotime( '+1 day', strtotime( $new_start ) ) );
						}
					} else {
						// nope. The event is a single day event. Add it to the array
						if ( ! isset( $this->event_ids_by_day[ $start ] ) ) {
							$this->event_ids_by_day[ $start ] = [];
						}

						$this->event_ids_by_day[ $start ][ $order_index ] = $event->ID;
					}
				}

				// Now that we've built our event_ids_by_day, let's array_unique and sort
				foreach ( $this->event_ids_by_day as &$day ) {
					$day = array_unique( $day );
					ksort( $day );
				}
			}

			if ( empty( $this->event_ids_by_day[ $date ] ) ) {
				return [];
			}

			return $this->event_ids_by_day[ $date ];
		}

		/**
		 * Get the events for a single day
		 *
		 * @param string $date
		 *
		 * @return WP_Query
		 */
		private function get_daily_events( $date ) {
			/**
			 * Filters the WP_Query object that will be returned for daily events on a date.
			 *
			 * If the value returned from this filter is not `null` then the method will bail
			 * and return the filter return value.
			 *
			 * @since 4.6.24
			 *
			 * @param WP_Query|null $daily_events The WP_Query object the template will loop on
			 *                                    to print the daily events; initially `null`.
			 * @param string        $date         The day date in `Y-m-d` format.
			 */
			$daily_events = apply_filters( 'tribe_events_month_daily_events', null, $date );
			if ( null !== $daily_events ) {
				return $daily_events;
			}

			$event_ids_on_date = $this->get_event_ids_by_day( $date );

			// post__in doesn't work when it's empty, so just don't run the query if there are no IDs
			if ( empty( $event_ids_on_date ) ) {
				return new WP_Query();
			}

			/**
			 * Since we've already got the post IDs of the events fitting the search criteria
			 * we can unset this to avoid furhter date-based filtering from happening.
			 */
			unset( $this->args['eventDate'] );

			/*
			 * This  will skip updating term and meta caches - those were already
			 * updated in `$this->set_events_in_month()`.
			 * We run another query to make sure the ordering applies correctly.
			 * Expected order of events: sticky events, ongoing multi day events, all day events, then by start time.
			 */
			$args = wp_parse_args(
				[
					'eventDisplay'           => 'month',
					'posts_per_page'         => $this->events_per_day,
					'post__in'               => $event_ids_on_date,
					'update_post_term_cache' => false,
					'update_post_meta_cache' => false,
					'no_found_rows'          => false,
					'do_not_inject_date'     => true,

					// Don't replace `orderby` without taking in cosideration `menu_order`.
					'orderby'                => 'post__in',
				],
				$this->args
			);

			// If the request is false or not set we assume the request is for all events, not just featured ones.
			if (
				tribe( 'tec.featured_events' )->featured_events_requested()
				|| (
					isset( $this->args['featured'] )
					&& tribe_is_truthy( $this->args['featured'] )
				)
			) {
				$args['featured'] = true;
			} else {
				/**
				 * Unset due to how queries featured argument is expected to be non-existent.
				 *
				 * @see #127272
				 */
				if ( isset( $args['featured'] ) ) {
					unset( $args['featured'] );
				}
			}

			/**
			  * Filter Daily Events Query Arguments.
			  *
			  * @param array $args an array of daily events query.
			  *
			  */
			 $args = apply_filters( 'tribe_events_month_daily_events_query_args', $args );

			return tribe_get_events( $args, true );
		}

		/**
		 * Sets up an array of $days based on the current query, that can be used in the calendar loop
		 *
		 */
		public function setup_view() {
			if ( $this->use_cache && $this->html_cache->get() !== false ) {
				return;
			}

			$days = [];

			$date = $this->first_grid_date; // Start with the first grid date

			// Populate complete date range including leading/trailing days from adjacent months
			while ( $date <= $this->final_grid_date ) {

				$day_events = $this->get_daily_events( $date );
				$day = (int) substr( $date, - 2 );

				$prev_month = (int) substr( $date, 5, 2 ) < (int) substr( $this->requested_date, 5, 2 );
				$next_month = (int) substr( $date, 5, 2 ) > (int) substr( $this->requested_date, 5, 2 );

				$month_type = self::CURRENT_MONTH;
				if ( $prev_month ) {
					$month_type = self::PREVIOUS_MONTH;
				}
				if ( $next_month ) {
					$month_type = self::NEXT_MONTH;
				}

				$days[] = [
					'daynum'       => $day,
					'daynum-id'    => Tribe__Events__Utils__Id_Generator::generate_id( $day, $day ),
					'date'         => $date,
					'events'       => $day_events,
					'total_events' => $day_events->found_posts,
					'view_more'    => ( $day_events->found_posts > $this->events_per_day && $this->events_per_day >= 1 ) ? self::view_more_link( $date ) : false,
					'month'        => $month_type,
				];

				// Record the indicies marking the portion of the array relating to the current month
				if ( ! isset( $this->current_month_begins ) && self::CURRENT_MONTH === $month_type ) {
					$this->current_month_begins = count( $days ) - 1;
				}
				if ( isset( $this->current_month_begins ) && ! isset( $this->current_month_ends ) && self::CURRENT_MONTH !== $month_type ) {
					$this->current_month_ends = count( $days ) - 1;
				}

				// Advance forward one day
				$date = date( Tribe__Date_Utils::DBDATEFORMAT, strtotime( "$date +1 day" ) );
			}

			// If the month ended without bleeding into the next month, our current_month_ends property may not be set
			if ( ! isset( $this->current_month_ends ) ) {
				$this->current_month_ends = count( $days ) - 1;
			}

			// store set of found days for use in calendar loop functions
			self::$calendar_days = $days;
		}

		/**
		 * Returns the requested date as a Y-m (yyyy-mm) formatted string.
		 *
		 * If the requested date is invalid (such as 1984-25) the current month is returned instead and
		 * an appropriate notice presented to the user.
		 *
		 * @return string
		 */
		protected function requested_date() {
			// We expect the date to be Y-m (yyyy-mm) format, ie year and date only
			$date = isset( $this->args['eventDate'] ) ? $this->args['eventDate'] : tribe_get_month_view_date();

			// Test and return unmodified if valid
			if ( false !== strtotime( $date . '-01' ) ) {
				return $date;
			} else {
				Tribe__Notices::set_notice( 'requested-date-invalid',
					sprintf( esc_html__( 'The requested date "%s" was not valid &ndash; showing the current month instead', 'the-events-calendar' ), esc_html( $date ) ) );

				return date_i18n( 'Y-m' );
			}
		}

		/**
		 * Loop through the $_REQUEST and find all tribe bar args.
		 *
		 * @return array
		 */
		protected static function get_tribe_bar_args() {
			$tribe_bar_args = [];
			foreach ( $_REQUEST as $key => $value ) {
				if ( $value && strpos( $key, 'tribe' ) === 0 && $key != 'tribe-bar-date' ) {
					$tribe_bar_args[ $key ] = $value;
				}
			}

			return $tribe_bar_args;
		}

		/**
		 * Return the date of the first day in the month view grid.
		 *
		 * This is not necessarily the 1st of the specified month, rather it is the date of the
		 * first grid cell which could be anything upto 6 days earlier than the 1st of the month.
		 *
		 * @param string  $month
		 * @param integer $start_of_week
		 *
		 * @return bool|string (Y-m-d)
		 */
		public static function calculate_first_cell_date( $month, $start_of_week = null ) {
			if ( null === $start_of_week ) {
				$start_of_week = (int) get_option( 'start_of_week', 0 );
			}

			$day_1 = Tribe__Date_Utils::first_day_in_month( $month );
			if ( $day_1 < $start_of_week ) {
				$day_1 += 7;
			}

			$diff = $day_1 - $start_of_week;
			if ( $diff >= 0 ) {
				$diff = "-$diff";
			}

			try {
				$date = new DateTime( $month );
				$date = new DateTime( $date->format( 'Y-m-01' ) );
				$date->modify( "$diff days" );

				return $date->format( Tribe__Date_Utils::DBDATEFORMAT );
			} catch ( Exception $e ) {
				return false;
			}
		}

		/**
		 * Return the date of the first day in the month view grid.
		 *
		 * This is not necessarily the last day of the specified month, rather it is the date of
		 * the final grid cell which could be anything upto 6 days into the next month.
		 *
		 * @param string  $month
		 * @param integer $start_of_week
		 *
		 * @return bool|string (Y-m-d)
		 */
		public static function calculate_final_cell_date( $month, $start_of_week = null ) {
			if ( null === $start_of_week ) {
				$start_of_week = (int) get_option( 'start_of_week', 0 );
			}

			$last_day    = Tribe__Date_Utils::last_day_in_month( $month );
			$end_of_week = Tribe__Date_Utils::week_ends_on( $start_of_week );
			if ( $end_of_week < $last_day ) {
				$end_of_week += 7;
			}

			$diff = $end_of_week - $last_day;
			if ( $diff >= 0 ) {
				$diff = "+$diff";
			}

			try {
				$date = new DateTime( $month );
				$date = new DateTime( $date->format( 'Y-m-t' ) );
				$date->modify( "$diff days" );

				return $date->format( Tribe__Date_Utils::DBDATEFORMAT );
			} catch ( Exception $e ) {
				return false;
			}
		}

		/**
		 * Checks whether there are more calendar days to display
		 *
		 * @return bool True if calendar days are available, false if not.
		 */
		public static function have_days() {
			if ( self::$current_day + 1 < count( self::$calendar_days ) ) {
				return true;
			} elseif ( self::$current_day + 1 == count( self::$calendar_days ) && count( self::$calendar_days ) > 0 ) {
				do_action( 'tribe_events_calendar_loop_end' );
				// Do some cleaning up after the loop
				self::rewind_days();
			}

			return false;
		}

		/**
		 * Advances the internal day counter (and week counter, if appropriate)
		 *
		 */
		public static function the_day() {
			if ( self::have_days() ) {
				self::$current_day ++;
				if ( self::$current_day % 7 == 0 ) {
					self::$current_week ++;
				}
			}
		}

		/**
		 * Rewind the posts and reset post index.
		 *
		 */
		public static function rewind_days() {
			self::$current_day  = - 1;
			self::$current_week = - 1;
		}

		/**
		 * Returns the current day according to self::$current_day
		 *
		 * @return array|boolean
		 */
		public static function get_current_day() {
			if ( count( self::$calendar_days ) && self::$current_day < count( self::$calendar_days ) && isset( self::$calendar_days[ self::$current_day ] ) ) {
				return self::$calendar_days[ self::$current_day ];
			}

			return false;
		}

		/**
		 * Generates and returns a set of classes for the current day.
		 *
		 * @return string
		 */
		public static function day_classes() {
			$current_day  = self::get_current_day();
			$calendar_day = Tribe__Date_Utils::date_only( $current_day['date'] );
			$today        = date_i18n( Tribe__Date_Utils::DBDATEFORMAT );

			// Start by determining which month we're looking at
			if ( $current_day['month'] == self::CURRENT_MONTH ) {
				$classes = 'tribe-events-thismonth';
			} else {
				$classes = 'tribe-events-othermonth';
			}

			// Check if the calendar day is in the past, present, or future
			if ( $calendar_day < $today ) {
				$classes .= ' tribe-events-past';
			} elseif ( $calendar_day === $today ) {
				$classes .= ' tribe-events-present';
			} elseif ( $calendar_day > $today ) {
				$classes .= ' tribe-events-future';
			}

			// The day has some events
			if ( $current_day['total_events'] > 0 ) {
				$classes .= ' tribe-events-has-events';
			}

			// Needed for mobile js
			$daynum   = date( 'd', strtotime( $calendar_day ) );
			$classes .= ' mobile-trigger tribe-event-day-' . $daynum;

			// Determine which column of the grid the day is in
			$column = ( self::$current_day ) - ( self::$current_week * 7 );
			if ( $column > 0 && ( $column % 4 == 0 || $column % 5 == 0 || $column % 6 == 0 ) ) {
				$classes .= ' tribe-events-right';
			}

			return $classes;
		}

		/**
		 * Returns self::$current_week
		 *
		 * @return int $current_week
		 */
		public static function get_current_week() {
			return self::$current_week;
		}

		/**
		 * Generates and returns a set of classes for the current day
		 *
		 * @param  string $classes = ''
		 *
		 * @return string Classes
		 */
		public function event_classes( $classes = '' ) {

			$day = self::get_current_day();

			if ( ! isset( $day['events'] ) ) {
				return $classes;
			}

			$post = $day['events']->post;

			// @todo [BTRIA-593]: Review whether the erasure of any existing classes is generally desirable.
			$classes = [];

			$tribe_cat_slugs = tribe_get_event_cat_slugs( $post->ID );
			foreach ( $tribe_cat_slugs as $tribe_cat_slug ) {
				$classes[] = 'tribe-events-category-' . $tribe_cat_slug;
			}
			$classes = array_merge( $classes, get_post_class( '', $post->ID ) );
			if ( $venue_id = tribe_get_venue_id( $post->ID ) ) {
				$classes[] = 'tribe-events-venue-' . $venue_id;
			}
			foreach ( tribe_get_organizer_ids( $post->ID ) as $organizer_id ) {
				$classes[] = 'tribe-events-organizer-' . $organizer_id;
			}

			if ( $day['events']->current_post + 1 == $day['events']->post_count ) {
				$classes[] = 'tribe-events-last';
			}

			// Mark 'featured' events
			if ( tribe( 'tec.featured_events' )->is_featured( $post->ID ) ) {
				$classes[] = 'tribe-event-featured';
			}

			return $classes;
		}

		/**
		 * Month View Ajax Handler
		 *
		 */
		public function ajax_response() {

			if ( isset( $_POST['eventDate'] ) && $_POST['eventDate'] ) {

				Tribe__Events__Query::init();

				Tribe__Events__Main::instance()->displaying = 'month';

				global $wp_query;

				$wp_query = tribe_get_events( $this->args, true );

				ob_start();

				tribe_get_view( 'month/content' );

				$response = [
					'html'    => ob_get_clean(),
					'success' => true,
					'view'    => 'month',
				];
				apply_filters( 'tribe_events_ajax_response', $response );
				header( 'Content-type: application/json' );
				echo json_encode( $response );
				die();
			}
		}

		public function has_events() {
			return (bool) $this->events_in_month;
		}

		/**
		 * Check if the month has events when all the filters have been applied.
		 *
		 * @since 4.6.19
		 *
		 * @return bool
		 */
		public function has_events_filtered() {

			if ( 'month' !== Tribe__Events__Main::instance()->displaying ) {
				return false;
			}

			if ( ! $wp_query = tribe_get_global_query_object() ) {
				return false;
			}

			// Get the date from the main query
			$event_date = $wp_query->get( 'eventDate' );

			// If we don't have the date, get the current date
			$month = empty( $event_date )
				? tribe_get_month_view_date()
				: $wp_query->get( 'eventDate' );

			// prepare the args for this month
			$args = [
				'eventDisplay'   => 'custom',
				'start_date'     => self::calculate_first_cell_date( $month ),
				'end_date'       => self::calculate_final_cell_date( $month ),
				'posts_per_page' => -1,
				'hide_upcoming'  => true,
			];

			// check if we should take care of taxonomy
			if ( $wp_query->get( Tribe__Events__Main::TAXONOMY, false ) !== false ) {
				$args[ Tribe__Events__Main::TAXONOMY ] = $wp_query->get( Tribe__Events__Main::TAXONOMY );
			}

			// See if we have events for
			$events = tribe_get_events( $args );

			return (bool) $events;

		}

	} // class Tribe__Events__Template__Month
}