Advanced Ads - Version 1.0.1

Version Description

  • several new hooks
  • seperated settings and debug page
  • few internal optimizations
  • few bug fixes for php < 5.3
Download this release

Release Info

Developer webzunft
Plugin Icon 128x128 Advanced Ads
Version 1.0.1
Comparing to
See all releases

Version 1.0.1

Files changed (48) hide show
  1. LICENSE.txt +339 -0
  2. README.txt +98 -0
  3. admin/assets/css/admin.css +50 -0
  4. admin/assets/css/index.php +1 -0
  5. admin/assets/js/admin.js +84 -0
  6. admin/assets/js/index.php +1 -0
  7. admin/assets/js/inline-edit-group-ads.js +101 -0
  8. admin/class-advanced-ads-admin.php +420 -0
  9. admin/includes/class-ad-groups-list-table.php +288 -0
  10. admin/includes/class-list-table.php +969 -0
  11. admin/includes/index.php +1 -0
  12. admin/views/ad-display-metabox.php +41 -0
  13. admin/views/ad-group-ads-inline-form.php +34 -0
  14. admin/views/ad-group-edit.php +80 -0
  15. admin/views/ad-group.php +101 -0
  16. admin/views/ad-main-metabox.php +21 -0
  17. admin/views/ad-parameters-metabox.php +15 -0
  18. admin/views/admin.php +25 -0
  19. admin/views/debug.php +16 -0
  20. admin/views/index.php +1 -0
  21. admin/views/settings.php +37 -0
  22. advanced-ads.php +79 -0
  23. assets/index.php +1 -0
  24. assets/screenshot-1.png +0 -0
  25. assets/screenshot-2.png +0 -0
  26. classes/ad.php +560 -0
  27. classes/ad_group.php +345 -0
  28. classes/ad_type_abstract.php +124 -0
  29. classes/ad_type_content.php +83 -0
  30. classes/ad_type_plain.php +75 -0
  31. includes/array_ad_conditions.php +77 -0
  32. includes/autoloader.php +31 -0
  33. includes/class_ajax_callbacks.php +99 -0
  34. includes/index.php +1 -0
  35. index.php +1 -0
  36. languages/index.php +1 -0
  37. languages/plugin-name.pot +31 -0
  38. public/assets/css/index.php +1 -0
  39. public/assets/css/public.css +1 -0
  40. public/assets/index.php +1 -0
  41. public/assets/js/index.php +1 -0
  42. public/assets/js/public.js +10 -0
  43. public/class-advanced-ads.php +553 -0
  44. public/functions.php +64 -0
  45. public/includes/index.php +1 -0
  46. public/views/index.php +1 -0
  47. public/views/public.php +16 -0
  48. uninstall.php +17 -0
LICENSE.txt ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+ Preamble
10
+
11
+ The licenses for most software are designed to take away your
12
+ freedom to share and change it. By contrast, the GNU General Public
13
+ License is intended to guarantee your freedom to share and change free
14
+ software--to make sure the software is free for all its users. This
15
+ General Public License applies to most of the Free Software
16
+ Foundation's software and to any other program whose authors commit to
17
+ using it. (Some other Free Software Foundation software is covered by
18
+ the GNU Lesser General Public License instead.) You can apply it to
19
+ your programs, too.
20
+
21
+ When we speak of free software, we are referring to freedom, not
22
+ price. Our General Public Licenses are designed to make sure that you
23
+ have the freedom to distribute copies of free software (and charge for
24
+ this service if you wish), that you receive source code or can get it
25
+ if you want it, that you can change the software or use pieces of it
26
+ in new free programs; and that you know you can do these things.
27
+
28
+ To protect your rights, we need to make restrictions that forbid
29
+ anyone to deny you these rights or to ask you to surrender the rights.
30
+ These restrictions translate to certain responsibilities for you if you
31
+ distribute copies of the software, or if you modify it.
32
+
33
+ For example, if you distribute copies of such a program, whether
34
+ gratis or for a fee, you must give the recipients all the rights that
35
+ you have. You must make sure that they, too, receive or can get the
36
+ source code. And you must show them these terms so they know their
37
+ rights.
38
+
39
+ We protect your rights with two steps: (1) copyright the software, and
40
+ (2) offer you this license which gives you legal permission to copy,
41
+ distribute and/or modify the software.
42
+
43
+ Also, for each author's protection and ours, we want to make certain
44
+ that everyone understands that there is no warranty for this free
45
+ software. If the software is modified by someone else and passed on, we
46
+ want its recipients to know that what they have is not the original, so
47
+ that any problems introduced by others will not reflect on the original
48
+ authors' reputations.
49
+
50
+ Finally, any free program is threatened constantly by software
51
+ patents. We wish to avoid the danger that redistributors of a free
52
+ program will individually obtain patent licenses, in effect making the
53
+ program proprietary. To prevent this, we have made it clear that any
54
+ patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+ The precise terms and conditions for copying, distribution and
57
+ modification follow.
58
+
59
+ GNU GENERAL PUBLIC LICENSE
60
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+ 0. This License applies to any program or other work which contains
63
+ a notice placed by the copyright holder saying it may be distributed
64
+ under the terms of this General Public License. The "Program", below,
65
+ refers to any such program or work, and a "work based on the Program"
66
+ means either the Program or any derivative work under copyright law:
67
+ that is to say, a work containing the Program or a portion of it,
68
+ either verbatim or with modifications and/or translated into another
69
+ language. (Hereinafter, translation is included without limitation in
70
+ the term "modification".) Each licensee is addressed as "you".
71
+
72
+ Activities other than copying, distribution and modification are not
73
+ covered by this License; they are outside its scope. The act of
74
+ running the Program is not restricted, and the output from the Program
75
+ is covered only if its contents constitute a work based on the
76
+ Program (independent of having been made by running the Program).
77
+ Whether that is true depends on what the Program does.
78
+
79
+ 1. You may copy and distribute verbatim copies of the Program's
80
+ source code as you receive it, in any medium, provided that you
81
+ conspicuously and appropriately publish on each copy an appropriate
82
+ copyright notice and disclaimer of warranty; keep intact all the
83
+ notices that refer to this License and to the absence of any warranty;
84
+ and give any other recipients of the Program a copy of this License
85
+ along with the Program.
86
+
87
+ You may charge a fee for the physical act of transferring a copy, and
88
+ you may at your option offer warranty protection in exchange for a fee.
89
+
90
+ 2. You may modify your copy or copies of the Program or any portion
91
+ of it, thus forming a work based on the Program, and copy and
92
+ distribute such modifications or work under the terms of Section 1
93
+ above, provided that you also meet all of these conditions:
94
+
95
+ a) You must cause the modified files to carry prominent notices
96
+ stating that you changed the files and the date of any change.
97
+
98
+ b) You must cause any work that you distribute or publish, that in
99
+ whole or in part contains or is derived from the Program or any
100
+ part thereof, to be licensed as a whole at no charge to all third
101
+ parties under the terms of this License.
102
+
103
+ c) If the modified program normally reads commands interactively
104
+ when run, you must cause it, when started running for such
105
+ interactive use in the most ordinary way, to print or display an
106
+ announcement including an appropriate copyright notice and a
107
+ notice that there is no warranty (or else, saying that you provide
108
+ a warranty) and that users may redistribute the program under
109
+ these conditions, and telling the user how to view a copy of this
110
+ License. (Exception: if the Program itself is interactive but
111
+ does not normally print such an announcement, your work based on
112
+ the Program is not required to print an announcement.)
113
+
114
+ These requirements apply to the modified work as a whole. If
115
+ identifiable sections of that work are not derived from the Program,
116
+ and can be reasonably considered independent and separate works in
117
+ themselves, then this License, and its terms, do not apply to those
118
+ sections when you distribute them as separate works. But when you
119
+ distribute the same sections as part of a whole which is a work based
120
+ on the Program, the distribution of the whole must be on the terms of
121
+ this License, whose permissions for other licensees extend to the
122
+ entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+ Thus, it is not the intent of this section to claim rights or contest
125
+ your rights to work written entirely by you; rather, the intent is to
126
+ exercise the right to control the distribution of derivative or
127
+ collective works based on the Program.
128
+
129
+ In addition, mere aggregation of another work not based on the Program
130
+ with the Program (or with a work based on the Program) on a volume of
131
+ a storage or distribution medium does not bring the other work under
132
+ the scope of this License.
133
+
134
+ 3. You may copy and distribute the Program (or a work based on it,
135
+ under Section 2) in object code or executable form under the terms of
136
+ Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+ a) Accompany it with the complete corresponding machine-readable
139
+ source code, which must be distributed under the terms of Sections
140
+ 1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+ b) Accompany it with a written offer, valid for at least three
143
+ years, to give any third party, for a charge no more than your
144
+ cost of physically performing source distribution, a complete
145
+ machine-readable copy of the corresponding source code, to be
146
+ distributed under the terms of Sections 1 and 2 above on a medium
147
+ customarily used for software interchange; or,
148
+
149
+ c) Accompany it with the information you received as to the offer
150
+ to distribute corresponding source code. (This alternative is
151
+ allowed only for noncommercial distribution and only if you
152
+ received the program in object code or executable form with such
153
+ an offer, in accord with Subsection b above.)
154
+
155
+ The source code for a work means the preferred form of the work for
156
+ making modifications to it. For an executable work, complete source
157
+ code means all the source code for all modules it contains, plus any
158
+ associated interface definition files, plus the scripts used to
159
+ control compilation and installation of the executable. However, as a
160
+ special exception, the source code distributed need not include
161
+ anything that is normally distributed (in either source or binary
162
+ form) with the major components (compiler, kernel, and so on) of the
163
+ operating system on which the executable runs, unless that component
164
+ itself accompanies the executable.
165
+
166
+ If distribution of executable or object code is made by offering
167
+ access to copy from a designated place, then offering equivalent
168
+ access to copy the source code from the same place counts as
169
+ distribution of the source code, even though third parties are not
170
+ compelled to copy the source along with the object code.
171
+
172
+ 4. You may not copy, modify, sublicense, or distribute the Program
173
+ except as expressly provided under this License. Any attempt
174
+ otherwise to copy, modify, sublicense or distribute the Program is
175
+ void, and will automatically terminate your rights under this License.
176
+ However, parties who have received copies, or rights, from you under
177
+ this License will not have their licenses terminated so long as such
178
+ parties remain in full compliance.
179
+
180
+ 5. You are not required to accept this License, since you have not
181
+ signed it. However, nothing else grants you permission to modify or
182
+ distribute the Program or its derivative works. These actions are
183
+ prohibited by law if you do not accept this License. Therefore, by
184
+ modifying or distributing the Program (or any work based on the
185
+ Program), you indicate your acceptance of this License to do so, and
186
+ all its terms and conditions for copying, distributing or modifying
187
+ the Program or works based on it.
188
+
189
+ 6. Each time you redistribute the Program (or any work based on the
190
+ Program), the recipient automatically receives a license from the
191
+ original licensor to copy, distribute or modify the Program subject to
192
+ these terms and conditions. You may not impose any further
193
+ restrictions on the recipients' exercise of the rights granted herein.
194
+ You are not responsible for enforcing compliance by third parties to
195
+ this License.
196
+
197
+ 7. If, as a consequence of a court judgment or allegation of patent
198
+ infringement or for any other reason (not limited to patent issues),
199
+ conditions are imposed on you (whether by court order, agreement or
200
+ otherwise) that contradict the conditions of this License, they do not
201
+ excuse you from the conditions of this License. If you cannot
202
+ distribute so as to satisfy simultaneously your obligations under this
203
+ License and any other pertinent obligations, then as a consequence you
204
+ may not distribute the Program at all. For example, if a patent
205
+ license would not permit royalty-free redistribution of the Program by
206
+ all those who receive copies directly or indirectly through you, then
207
+ the only way you could satisfy both it and this License would be to
208
+ refrain entirely from distribution of the Program.
209
+
210
+ If any portion of this section is held invalid or unenforceable under
211
+ any particular circumstance, the balance of the section is intended to
212
+ apply and the section as a whole is intended to apply in other
213
+ circumstances.
214
+
215
+ It is not the purpose of this section to induce you to infringe any
216
+ patents or other property right claims or to contest validity of any
217
+ such claims; this section has the sole purpose of protecting the
218
+ integrity of the free software distribution system, which is
219
+ implemented by public license practices. Many people have made
220
+ generous contributions to the wide range of software distributed
221
+ through that system in reliance on consistent application of that
222
+ system; it is up to the author/donor to decide if he or she is willing
223
+ to distribute software through any other system and a licensee cannot
224
+ impose that choice.
225
+
226
+ This section is intended to make thoroughly clear what is believed to
227
+ be a consequence of the rest of this License.
228
+
229
+ 8. If the distribution and/or use of the Program is restricted in
230
+ certain countries either by patents or by copyrighted interfaces, the
231
+ original copyright holder who places the Program under this License
232
+ may add an explicit geographical distribution limitation excluding
233
+ those countries, so that distribution is permitted only in or among
234
+ countries not thus excluded. In such case, this License incorporates
235
+ the limitation as if written in the body of this License.
236
+
237
+ 9. The Free Software Foundation may publish revised and/or new versions
238
+ of the General Public License from time to time. Such new versions will
239
+ be similar in spirit to the present version, but may differ in detail to
240
+ address new problems or concerns.
241
+
242
+ Each version is given a distinguishing version number. If the Program
243
+ specifies a version number of this License which applies to it and "any
244
+ later version", you have the option of following the terms and conditions
245
+ either of that version or of any later version published by the Free
246
+ Software Foundation. If the Program does not specify a version number of
247
+ this License, you may choose any version ever published by the Free Software
248
+ Foundation.
249
+
250
+ 10. If you wish to incorporate parts of the Program into other free
251
+ programs whose distribution conditions are different, write to the author
252
+ to ask for permission. For software which is copyrighted by the Free
253
+ Software Foundation, write to the Free Software Foundation; we sometimes
254
+ make exceptions for this. Our decision will be guided by the two goals
255
+ of preserving the free status of all derivatives of our free software and
256
+ of promoting the sharing and reuse of software generally.
257
+
258
+ NO WARRANTY
259
+
260
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+ REPAIR OR CORRECTION.
269
+
270
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+ POSSIBILITY OF SUCH DAMAGES.
279
+
280
+ END OF TERMS AND CONDITIONS
281
+
282
+ How to Apply These Terms to Your New Programs
283
+
284
+ If you develop a new program, and you want it to be of the greatest
285
+ possible use to the public, the best way to achieve this is to make it
286
+ free software which everyone can redistribute and change under these terms.
287
+
288
+ To do so, attach the following notices to the program. It is safest
289
+ to attach them to the start of each source file to most effectively
290
+ convey the exclusion of warranty; and each file should have at least
291
+ the "copyright" line and a pointer to where the full notice is found.
292
+
293
+ <one line to give the program's name and a brief idea of what it does.>
294
+ Copyright (C) <year> <name of author>
295
+
296
+ This program is free software; you can redistribute it and/or modify
297
+ it under the terms of the GNU General Public License as published by
298
+ the Free Software Foundation; either version 2 of the License, or
299
+ (at your option) any later version.
300
+
301
+ This program is distributed in the hope that it will be useful,
302
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304
+ GNU General Public License for more details.
305
+
306
+ You should have received a copy of the GNU General Public License along
307
+ with this program; if not, write to the Free Software Foundation, Inc.,
308
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
+
310
+ Also add information on how to contact you by electronic and paper mail.
311
+
312
+ If the program is interactive, make it output a short notice like this
313
+ when it starts in an interactive mode:
314
+
315
+ Gnomovision version 69, Copyright (C) year name of author
316
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
+ This is free software, and you are welcome to redistribute it
318
+ under certain conditions; type `show c' for details.
319
+
320
+ The hypothetical commands `show w' and `show c' should show the appropriate
321
+ parts of the General Public License. Of course, the commands you use may
322
+ be called something other than `show w' and `show c'; they could even be
323
+ mouse-clicks or menu items--whatever suits your program.
324
+
325
+ You should also get your employer (if you work as a programmer) or your
326
+ school, if any, to sign a "copyright disclaimer" for the program, if
327
+ necessary. Here is a sample; alter the names:
328
+
329
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
+
332
+ <signature of Ty Coon>, 1 April 1989
333
+ Ty Coon, President of Vice
334
+
335
+ This General Public License does not permit incorporating your program into
336
+ proprietary programs. If your program is a subroutine library, you may
337
+ consider it more useful to permit linking proprietary applications with the
338
+ library. If this is what you want to do, use the GNU Lesser General
339
+ Public License instead of this License.
README.txt ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Advanced Ads ===
2
+ Contributors: webzunft
3
+ Donate link: http://webgilde.com/
4
+ Tags: ads, ad, adsense
5
+ Requires at least: 3.5
6
+ Tested up to: 3.9.1
7
+ Stable tag: 1.0.1
8
+ License: GPLv2 or later
9
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
+
11
+ Manage and optimize your ads in WordPress with this easy to use and extendable plugin.
12
+
13
+ == Description ==
14
+
15
+ = Features =
16
+
17
+ * create and manage ads
18
+ * deliver ads based on conditions (e.g. post type, post id, category)
19
+ * display ad in template files (with functions)
20
+ * display ad in post content (with shortcodes)
21
+ * group ads
22
+ * display ads from groups with customized ad weight
23
+ * integrated into WordPress to be as much compatible as possible with WP standards, functions and plugins
24
+ * easily customizable by any WordPress plugin developer
25
+
26
+ = Insights for developers =
27
+
28
+ * ads are custom post types
29
+ * many filters and hooks to add new functions without hacking the plugin and keeping it updateable
30
+ * e.g. add your own ad types and display conditions using the api
31
+ * an extended online manual is in progress
32
+
33
+ == Installation ==
34
+
35
+ This section describes how to install the plugin and get it working.
36
+
37
+ e.g.
38
+
39
+ = Using The WordPress Dashboard =
40
+
41
+ 1. Navigate to the 'Add New' in the plugins dashboard
42
+ 2. Search for 'plugin-name'
43
+ 3. Click 'Install Now'
44
+ 4. Activate the plugin on the Plugin dashboard
45
+
46
+ = Uploading in WordPress Dashboard =
47
+
48
+ 1. Navigate to the 'Add New' in the plugins dashboard
49
+ 2. Navigate to the 'Upload' area
50
+ 3. Select `plugin-name.zip` from your computer
51
+ 4. Click 'Install Now'
52
+ 5. Activate the plugin in the Plugin dashboard
53
+
54
+ = Using FTP =
55
+
56
+ 1. Download `plugin-name.zip`
57
+ 2. Extract the `plugin-name` directory to your computer
58
+ 3. Upload the `plugin-name` directory to the `/wp-content/plugins/` directory
59
+ 4. Activate the plugin in the Plugin dashboard
60
+
61
+ == Displaying Ads ==
62
+
63
+ You can use functions and shortcodes to display ads and ad groups.
64
+
65
+ The integers in this example are the IDs of the elements.
66
+
67
+ Use these shortcode to insert an ad or ad group into your post/page.
68
+
69
+ `[the_ad id="24"]`
70
+ `[the_ad_group id="5"]`
71
+
72
+ Use these functions to insert an ad or ad group into your template file.
73
+
74
+ `<?php the_ad(24); ?>`
75
+ `<?php the_ad_group(5); ?>`
76
+
77
+ == Frequently Asked Questions ==
78
+
79
+ = Is there a revenue share? =
80
+
81
+ There is no revenue share. Advanced Ads doesn’t alter your ad codes in a way that you earn less than you would directly including the ad code in your template.
82
+
83
+ == Screenshots ==
84
+
85
+ 1. Create an ad almost like you would create an article or page.
86
+ 2. Choose from various conditions where and where not to display your ad.
87
+
88
+ == Changelog ==
89
+
90
+ = 1.0.1 =
91
+
92
+ * several new hooks
93
+ * seperated settings and debug page
94
+ * few internal optimizations
95
+ * few bug fixes for php < 5.3
96
+
97
+ = 1.0 =
98
+ * first release
admin/assets/css/admin.css ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * AD EDIT PAGE
3
+ */
4
+ #ad-main-box { overflow: hidden; }
5
+ .post-type-advanced_ads .meta-box-sortables .hndle { display: none; }
6
+ .post-type-advanced_ads .meta-box-sortables .handlediv { display: none; }
7
+ .post-type-advanced_ads #poststuff .meta-box-sortables .inside {
8
+ margin: 0;
9
+ padding: 0;
10
+ }
11
+ .post-type-advanced_ads .meta-box-sortables .inside > * {
12
+ margin: 20px 10px;
13
+ }
14
+ .post-type-advanced_ads .meta-box-sortables .inside h4 {
15
+ background: linear-gradient(to top, #ECECEC, #F9F9F9) repeat scroll 0 0 #F1F1F1;
16
+ font-size: 15px;
17
+ font-weight: 400;
18
+ line-height: 1;
19
+ margin: 0;
20
+ padding: 10px 10px 5px;
21
+ }
22
+ #advanced-ad-type .description {
23
+ display: block;
24
+ margin-left: 24px;
25
+ }
26
+ .post-type-advanced_ads #advanced_ad_content_others textarea {
27
+ width: 100%;
28
+ height: 20em;
29
+ }
30
+
31
+ .post-type-advanced_ads #advanced-ad-conditions {
32
+ text-align: left;
33
+ }
34
+ .post-type-advanced_ads #advads-ad-content-plain {
35
+ width: 100%;
36
+ }
37
+ .post-type-advanced_ads #ad-parameters-box .advads-ad-parameters-spinner { display: block; float: none; }
38
+
39
+ /**
40
+ AD GROUP LIST
41
+ */
42
+ .advads-groups-ads-list { margin: 0; }
43
+ .ad-group-ads-form table td { margin: 0; padding: 3px 5px 3px 0; }
44
+ .ad-group-ads-form table td:first-child { font-weight: bold; }
45
+ .ad-group-ads-form table td.ad-group-ads-weight input { width: 3em; }
46
+
47
+ /**
48
+ GENERAL ELEMENTS
49
+ */
50
+ .advads-toggle-link { cursor: pointer; }
admin/assets/css/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php // Silence is golden
admin/assets/js/admin.js ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function($) {
2
+ "use strict";
3
+ /*
4
+ function load_content_editor( ad_type ) {
5
+ $.ajax({
6
+ type: 'POST',
7
+ url: ajaxurl,
8
+ data: {
9
+ 'action': 'load_content_editor',
10
+ 'type' : ad_type,
11
+ 'ad_id' : $('#post_ID').val()
12
+ },
13
+ success:function(data, textStatus, XMLHttpRequest){
14
+ // toggle main content field
15
+ if(data == 'content') {
16
+ $('#advanced_ad_content_others').html(''); // clear other editors
17
+ $('#advanced_ad_content').show();
18
+ } else {
19
+ $('#advanced_ad_content').hide();
20
+ $('#advanced_ad_content_others').html(data);
21
+ }
22
+ },
23
+ error: function(MLHttpRequest, textStatus, errorThrown){
24
+ $('#advanced_ad_content_others').html(errorThrown);
25
+ }
26
+ });
27
+ };
28
+
29
+ // load content editor on page load
30
+ if($('#advanced_ad_type input').length > 0) {
31
+ var ad_type = $('#advanced_ad_type input').val();
32
+ load_content_editor(ad_type);
33
+ }
34
+
35
+ $(document).on('change', '#advanced_ad_type input', function(){
36
+ var ad_type = $(this).val()
37
+ load_content_editor( ad_type );
38
+ });
39
+ */
40
+
41
+ function advads_load_ad_type_parameter_metabox(ad_type) {
42
+ $('#advanced-ads-ad-parameters').html('<span class="spinner advads-ad-parameters-spinner"></span>');
43
+ $.ajax({
44
+ type: 'POST',
45
+ url: ajaxurl,
46
+ data: {
47
+ 'action': 'load_ad_parameters_metabox',
48
+ 'ad_type': ad_type,
49
+ 'ad_id': $('#post_ID').val()
50
+ },
51
+ success: function(data, textStatus, XMLHttpRequest) {
52
+ // toggle main content field
53
+ if (data) {
54
+ $('#advanced-ads-ad-parameters').html(data);
55
+ }
56
+ },
57
+ error: function(MLHttpRequest, textStatus, errorThrown) {
58
+ $('#advanced-ads-ad-parameters').html(errorThrown);
59
+ }
60
+ });
61
+ }
62
+ ;
63
+
64
+ $(document).on('change', '#advanced-ad-type input', function() {
65
+ var ad_type = $(this).val()
66
+ advads_load_ad_type_parameter_metabox(ad_type);
67
+ });
68
+
69
+ // empty / clear input condition fields in the same row as the clear button
70
+ $('#advanced-ad-conditions .clear-radio').click(function() {
71
+ $(this).closest('tr').find('input[type="radio"]').prop('checked', false);
72
+ $(this).closest('tr').find('input[type="text"]').val('');
73
+ });
74
+
75
+ })
76
+
77
+ /**
78
+ * toggle content elements (hide/show)
79
+ *
80
+ * @param selector jquery selector
81
+ */
82
+ function advads_toggle(selector) {
83
+ jQuery(selector).slideToggle();
84
+ }
admin/assets/js/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php // Silence is golden
admin/assets/js/inline-edit-group-ads.js ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* saving ad group ad settings */
2
+
3
+ var inlineEditAdGroupAds;
4
+ (function($) {
5
+ inlineEditAdGroupAds = {
6
+ init: function() {
7
+ var t = this;
8
+ $('#the-list').on('click', 'a.edit-ad-group-ads', function() {
9
+ inlineEditAdGroupAds.edit(this);
10
+ return false;
11
+ });
12
+ $('#the-list').on('click', 'a.cancel', function() {
13
+ return inlineEditAdGroupAds.revert();
14
+ });
15
+ $('#the-list').on('click', 'a.save', function() {
16
+ return inlineEditAdGroupAds.save(this);
17
+ });
18
+ $('#the-list').on('keydown', 'input, select', function() {
19
+ if (e.which === 13) {
20
+ return inlineEditAdGroupAds.save(this);
21
+ }
22
+ });
23
+ $('#posts-filter input[type="submit"]').mousedown(function() {
24
+ t.revert();
25
+ });
26
+ },
27
+ edit: function(link) {
28
+ var td, id, t = this;
29
+ // get group id
30
+ id = t.getId(link);
31
+ // get container
32
+ td = $(link).parents('td');
33
+ // load form with information
34
+ params = {
35
+ action: 'advads-ad-group-ads-form',
36
+ group_id: id,
37
+ };
38
+ $.post(ajaxurl, params,
39
+ // append return
40
+ function(r) {
41
+ if (r) {
42
+ // hide all child elements
43
+ td.children('*').hide();
44
+ // display the form
45
+ $(r).appendTo(td);
46
+ }
47
+ }
48
+ );
49
+ return false;
50
+ },
51
+ save: function(link) {
52
+ var params, td, id, t = this;
53
+ // get group id
54
+ id = t.getId(link);
55
+ // get container
56
+ td = $(link).parents('td');
57
+ td.find('.ad-group-ads-form .spinner').show();
58
+ params = {
59
+ action: 'advads-ad-group-ads-form-save',
60
+ group_id: id,
61
+ fields: ''
62
+ };
63
+ params.fields = td.find(':input').serialize();
64
+ // make ajax request
65
+ $.post(ajaxurl, params, function(r) {
66
+ td.find('.ad-group-ads-form .spinner').hide();
67
+ if (r) {
68
+ t.revert(); // show normal table
69
+
70
+ $.each(r, function(key, value){
71
+ // search the field with the ad weight and change the value
72
+ td.find('.ad-weight-' + key).html(value);
73
+ })
74
+ }
75
+
76
+ }, "json"
77
+ );
78
+ return false;
79
+ },
80
+ // remove edit form and display the other elements again
81
+ revert: function() {
82
+ var td = $('table.widefat .ad-group-ads-form').parents('td');
83
+ if (td) {
84
+ $('table.widefat .spinner').hide();
85
+ td.find('.ad-group-ads-form').remove();
86
+ td.find('*').show();
87
+ }
88
+
89
+ return false;
90
+ },
91
+ // get the id of the group from the link clicked
92
+ getId: function(link) {
93
+ groupid = $(link).parents('td').find('.ad-group-id').val();
94
+ return parseInt(groupid);
95
+ ;
96
+ }
97
+ };
98
+ $(document).ready(function() {
99
+ inlineEditAdGroupAds.init();
100
+ });
101
+ })(jQuery);
admin/class-advanced-ads-admin.php ADDED
@@ -0,0 +1,420 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Advanced Ads.
5
+ *
6
+ * @package Advanced_Ads_Admin
7
+ * @author Thomas Maier <thomas.maier@webgilde.com>
8
+ * @license GPL-2.0+
9
+ * @link http://webgilde.com
10
+ * @copyright 2013 Thomas Maier, webgilde GmbH
11
+ */
12
+
13
+ /**
14
+ * Plugin class. This class should ideally be used to work with the
15
+ * administrative side of the WordPress site.
16
+ *
17
+ * *
18
+ * @package Advanced_Ads_Admin
19
+ * @author Thomas Maier <thomas.maier@webgilde.com>
20
+ */
21
+ class Advanced_Ads_Admin {
22
+
23
+ /**
24
+ * Instance of this class.
25
+ *
26
+ * @since 1.0.0
27
+ * @var object
28
+ */
29
+ protected static $instance = null;
30
+
31
+ /**
32
+ * Slug of the settings page
33
+ *
34
+ * @since 1.0.0
35
+ * @var string
36
+ */
37
+ public $plugin_screen_hook_suffix = null;
38
+
39
+ /**
40
+ * Slug of the ad group page
41
+ *
42
+ * @since 1.0.0
43
+ * @var string
44
+ */
45
+ protected $ad_group_hook_suffix = null;
46
+
47
+ /**
48
+ * general plugin slug
49
+ *
50
+ * @since 1.0.0
51
+ * @var string
52
+ */
53
+ protected $plugin_slug = '';
54
+
55
+ /**
56
+ * post type slug
57
+ *
58
+ * @since 1.0.0
59
+ * @var string
60
+ */
61
+ protected $post_type = '';
62
+
63
+ /**
64
+ * Initialize the plugin by loading admin scripts & styles and adding a
65
+ * settings page and menu.
66
+ *
67
+ * @since 1.0.0
68
+ */
69
+ private function __construct() {
70
+
71
+ /*
72
+ * Call $plugin_slug from public plugin class.
73
+ *
74
+ */
75
+ $plugin = Advanced_Ads::get_instance();
76
+ $this->plugin_slug = $plugin->get_plugin_slug();
77
+ $this->post_type = constant("Advanced_Ads::POST_TYPE_SLUG");
78
+
79
+ // Load admin style sheet and JavaScript.
80
+ add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_styles'));
81
+ add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
82
+
83
+ // Add menu items
84
+ add_action('admin_menu', array($this, 'add_ad_group_menu'));
85
+ add_action('admin_menu', array($this, 'add_plugin_admin_menu'));
86
+
87
+ add_action('admin_init', array($this, 'add_meta_boxes'));
88
+
89
+ // save ads post type
90
+ add_action('save_post', array($this, 'save_ad'));
91
+
92
+ // settings handling
93
+ add_action('admin_init', array($this, 'settings_init'));
94
+
95
+ // Add an action link pointing to the options page.
96
+ $plugin_basename = plugin_basename(plugin_dir_path('__DIR__') . $this->plugin_slug . '.php');
97
+ add_filter('plugin_action_links_' . $plugin_basename, array($this, 'add_action_links'));
98
+ }
99
+
100
+ /**
101
+ * Return an instance of this class.
102
+ *
103
+ * @since 1.0.0
104
+ *
105
+ * @return object A single instance of this class.
106
+ */
107
+ public static function get_instance() {
108
+
109
+ // If the single instance hasn't been set, set it now.
110
+ if (null == self::$instance) {
111
+ self::$instance = new self;
112
+ }
113
+
114
+ return self::$instance;
115
+ }
116
+
117
+ /**
118
+ * Register and enqueue admin-specific style sheet.
119
+ *
120
+ * @since 1.0.0
121
+ *
122
+ * @return null Return early if no settings page is registered.
123
+ */
124
+ public function enqueue_admin_styles() {
125
+
126
+ global $post;
127
+ if (!isset($this->plugin_screen_hook_suffix) && Advanced_Ads::POST_TYPE_SLUG != $post->type) {
128
+ return;
129
+ }
130
+
131
+ wp_enqueue_style($this->plugin_slug . '-admin-styles', plugins_url('assets/css/admin.css', __FILE__), array(), Advanced_Ads::VERSION);
132
+ }
133
+
134
+ /**
135
+ * Register and enqueue admin-specific JavaScript.
136
+ *
137
+ * @since 1.0.0
138
+ *
139
+ * @return null Return early if no settings page is registered.
140
+ */
141
+ public function enqueue_admin_scripts() {
142
+
143
+ global $post;
144
+ if (!isset($this->plugin_screen_hook_suffix) && Advanced_Ads::POST_TYPE_SLUG != $post->type) {
145
+ return;
146
+ }
147
+
148
+ wp_enqueue_script($this->plugin_slug . '-admin-script', plugins_url('assets/js/admin.js', __FILE__), array('jquery'), Advanced_Ads::VERSION);
149
+
150
+ // just register this script for later inclusion on ad group list page
151
+ wp_register_script('inline-edit-group-ads', plugins_url('assets/js/inline-edit-group-ads.js', __FILE__), array('jquery'), Advanced_Ads::VERSION);
152
+
153
+ }
154
+
155
+ /**
156
+ * Register the administration menu for this plugin into the WordPress Dashboard menu.
157
+ *
158
+ * @since 1.0.0
159
+ */
160
+ public function add_plugin_admin_menu() {
161
+
162
+ // add settings page
163
+ $this->plugin_screen_hook_suffix = add_submenu_page(
164
+ 'edit.php?post_type=' . Advanced_Ads::POST_TYPE_SLUG, __('Advanced Ads Settings', $this->plugin_slug), __('Settings', $this->plugin_slug), 'manage_options', $this->plugin_slug . '-settings', array($this, 'display_plugin_settings_page')
165
+ );
166
+ add_submenu_page(
167
+ null, __('Advanced Ads Debugging', $this->plugin_slug), __('Debug', $this->plugin_slug), 'manage_options', $this->plugin_slug . '-debug', array($this, 'display_plugin_debug_page')
168
+ );
169
+ }
170
+
171
+ /**
172
+ * Render the settings page
173
+ *
174
+ * @since 1.0.0
175
+ */
176
+ public function display_plugin_settings_page() {
177
+ include_once( 'views/settings.php' );
178
+ }
179
+
180
+ /**
181
+ * Render the debug page
182
+ *
183
+ * @since 1.0.1
184
+ */
185
+ public function display_plugin_debug_page() {
186
+ // load array with ads by condition
187
+ $plugin = Advanced_Ads::get_instance();
188
+ $ads_by_conditions = $plugin->get_ads_by_conditions_array();
189
+
190
+ include_once( 'views/debug.php' );
191
+ }
192
+
193
+ /**
194
+ * Register ad group taxonomy page
195
+ *
196
+ * @since 1.0.0
197
+ */
198
+ public function add_ad_group_menu() {
199
+
200
+ $this->ad_group_hook_suffix = add_submenu_page(
201
+ 'edit.php?post_type=' . Advanced_Ads::POST_TYPE_SLUG, __('Ad Groups', $this->plugin_slug), __('Ad Groups', $this->plugin_slug), 'manage_options', $this->plugin_slug . '-groups', array($this, 'ad_group_admin_page')
202
+ );
203
+ }
204
+
205
+ /**
206
+ * Render the ad group page
207
+ *
208
+ * @since 1.0.0
209
+ */
210
+ public function ad_group_admin_page() {
211
+
212
+ $taxonomy = Advanced_Ads::AD_GROUP_TAXONOMY;
213
+ $post_type = Advanced_Ads::POST_TYPE_SLUG;
214
+ $tax = get_taxonomy($taxonomy);
215
+
216
+ $action = $this->current_action();
217
+
218
+ // handle new and updated groups
219
+ if ($action == 'editedgroup') {
220
+ $group_id = (int) $_POST['group_id'];
221
+ check_admin_referer('update-group_' . $group_id);
222
+
223
+ if (!current_user_can($tax->cap->edit_terms))
224
+ wp_die(__('Cheatin&#8217; uh?'));
225
+
226
+ // handle new groups
227
+ if ($group_id == 0) {
228
+ $ret = wp_insert_term($_POST['name'], $taxonomy, $_POST);
229
+ if ($ret && !is_wp_error($ret))
230
+ $forced_message = 1;
231
+ else
232
+ $forced_message = 4;
233
+ // handle group updates
234
+ } else {
235
+ $tag = get_term($group_id, $taxonomy);
236
+ if (!$tag)
237
+ wp_die(__('You attempted to edit an item that doesn&#8217;t exist. Perhaps it was deleted?'));
238
+
239
+ $ret = wp_update_term($group_id, $taxonomy, $_POST);
240
+ if ($ret && !is_wp_error($ret))
241
+ $forced_message = 3;
242
+ else
243
+ $forced_message = 5;
244
+ }
245
+ // deleting items
246
+ } elseif($action == 'delete'){
247
+ $group_id = (int) $_REQUEST['group_id'];
248
+ check_admin_referer('delete-tag_' . $group_id);
249
+
250
+ if (!current_user_can($tax->cap->delete_terms))
251
+ wp_die(__('Cheatin&#8217; uh?'));
252
+
253
+ wp_delete_term($group_id, $taxonomy);
254
+
255
+ $forced_message = 2;
256
+ }
257
+
258
+ // handly views
259
+ switch ($action) {
260
+ case 'edit' :
261
+ $title = $tax->labels->edit_item;
262
+ if (isset($_REQUEST['group_id'])) {
263
+ $group_id = absint($_REQUEST['group_id']);
264
+ $tag = get_term($group_id, $taxonomy, OBJECT, 'edit');
265
+ } else {
266
+ $group_id = 0;
267
+ $tag = false;
268
+ }
269
+
270
+ require_once( 'views/ad-group-edit.php' );
271
+ break;
272
+
273
+ default :
274
+ $title = $tax->labels->name;
275
+ // load needed classes
276
+ include_once( 'includes/class-list-table.php' );
277
+ include_once( 'includes/class-ad-groups-list-table.php' );
278
+ // load template
279
+ include_once( 'views/ad-group.php' );
280
+ }
281
+ }
282
+
283
+ /**
284
+ * returns a link to the ad group list page
285
+ *
286
+ * @since 1.0.0
287
+ * @param arr $args additional arguments, e.g. action or group_id
288
+ * @return string admin url
289
+ */
290
+ static function group_page_url($args = array()) {
291
+ $plugin = Advanced_Ads::get_instance();
292
+
293
+ $defaultargs = array(
294
+ 'post_type' => constant("Advanced_Ads::POST_TYPE_SLUG"),
295
+ 'page' => 'advanced-ads-groups',
296
+ );
297
+ $args = $args + $defaultargs;
298
+
299
+ return add_query_arg($args, admin_url('edit.php'));
300
+ }
301
+
302
+ /**
303
+ * Add settings action link to the plugins page.
304
+ *
305
+ * @since 1.0.0
306
+ */
307
+ public function add_action_links($links) {
308
+
309
+ return array_merge(
310
+ array(
311
+ 'settings' => '<a href="' . admin_url('edit.php?post_type=advanced_ads&page=advanced-ads-settings') . '">' . __('Settings', $this->plugin_slug) . '</a>'
312
+ ), $links
313
+ );
314
+ }
315
+
316
+ /**
317
+ * Add meta boxes
318
+ *
319
+ * @since 1.0.0
320
+ */
321
+ public function add_meta_boxes() {
322
+ global $_wp_post_type_features;
323
+
324
+ add_meta_box(
325
+ 'ad-main-box', __('Ad Main', $this->plugin_slug), array($this, 'markup_meta_boxes'), Advanced_Ads::POST_TYPE_SLUG, 'normal', 'high'
326
+ );
327
+ add_meta_box(
328
+ 'ad-parameters-box', __('Fine tune your ad', $this->plugin_slug), array($this, 'markup_meta_boxes'), Advanced_Ads::POST_TYPE_SLUG, 'normal', 'high'
329
+ );
330
+ add_meta_box(
331
+ 'ad-display-box', __('Where to display your ads', $this->plugin_slug), array($this, 'markup_meta_boxes'), Advanced_Ads::POST_TYPE_SLUG, 'normal', 'high'
332
+ );
333
+ }
334
+
335
+ /**
336
+ * load templates for all meta boxes
337
+ *
338
+ * @since 1.0.0
339
+ * @param obj $post
340
+ * @param array $box
341
+ * @todo move ad initialization to main function and just global it
342
+ */
343
+ public function markup_meta_boxes($post, $box) {
344
+ $ad = new Advads_Ad($post->ID);
345
+
346
+ switch ($box['id']) {
347
+ case 'ad-main-box':
348
+ $view = 'ad-main-metabox.php';
349
+ break;
350
+ case 'ad-parameters-box':
351
+ $view = 'ad-parameters-metabox.php';
352
+ break;
353
+ case 'ad-display-box':
354
+ $view = 'ad-display-metabox.php';
355
+ break;
356
+ }
357
+
358
+ if (empty($view))
359
+ return;
360
+ $view = plugin_dir_path(__FILE__) . 'views/' . $view;
361
+ if (is_file($view)) {
362
+ require_once( $view );
363
+ }
364
+ }
365
+
366
+ /**
367
+ * prepare the ad post type to be saved
368
+ *
369
+ * @since 1.0.0
370
+ * @param int $post_id id of the post
371
+ * @todo handling this more dynamic based on ad type
372
+ */
373
+ public function save_ad($post_id) {
374
+
375
+ // only use for ads, no other post type
376
+ if (!isset($_POST['post_type']) || $this->post_type != $_POST['post_type'] || !isset($_POST['advanced_ad']['type'])) {
377
+ return;
378
+ }
379
+
380
+ // get ad object
381
+ $ad = new Advads_Ad($post_id);
382
+ if (!$ad instanceof Advads_Ad)
383
+ return;
384
+
385
+ $ad->type = $_POST['advanced_ad']['type'];
386
+ if(!empty($_POST['advanced_ad']['content']))
387
+ $ad->content = $_POST['advanced_ad']['content'];
388
+ else $ad->content = '';
389
+ $ad->conditions = $_POST['advanced_ad']['conditions'];
390
+
391
+ $ad->save();
392
+ }
393
+
394
+ /**
395
+ * get action from the params
396
+ *
397
+ * @since 1.0.0
398
+ */
399
+ public function current_action() {
400
+ if (isset($_REQUEST['action']) && -1 != $_REQUEST['action'])
401
+ return $_REQUEST['action'];
402
+
403
+ return false;
404
+ }
405
+
406
+ /**
407
+ * initialize settings
408
+ *
409
+ * @since 1.0.1
410
+ */
411
+ public function settings_init(){
412
+
413
+ // no additional settings registered yet, but some addons might need this
414
+
415
+ // register settings
416
+ register_setting($this->plugin_screen_hook_suffix, 'advancedads');
417
+ }
418
+
419
+
420
+ }
admin/includes/class-ad-groups-list-table.php ADDED
@@ -0,0 +1,288 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Groups List Table class.
5
+ *
6
+ * derrived from WP_Terms_List_Table
7
+ *
8
+ * @package WordPress
9
+ * @subpackage List_Table
10
+ * @since 3.1.0
11
+ * @access private
12
+ */
13
+ class AdvAds_Groups_List_Table extends AdvAds_List_Table {
14
+
15
+ /**
16
+ * constructor
17
+ *
18
+ * @since 1.0.0
19
+ * @global type $status
20
+ * @global type $page
21
+ */
22
+ function __construct() {
23
+ global $status, $page;
24
+
25
+ parent::__construct(array(
26
+ 'plural' => 'adgroups',
27
+ 'singular' => 'adgroup',
28
+ ));
29
+
30
+ $this->post_type = Advanced_Ads::POST_TYPE_SLUG;
31
+ $this->taxonomy = Advanced_Ads::AD_GROUP_TAXONOMY;
32
+ }
33
+
34
+ /**
35
+ * default column handling
36
+ *
37
+ * @since 1.0.0
38
+ * @param type $item
39
+ * @param type $column_name
40
+ * @return output for the column
41
+ */
42
+ function column_default($item, $column_name) {
43
+ return apply_filters("manage_{$this->taxonomy}_{$column_name}_column", '', $column_name, $item->term_id);
44
+ }
45
+
46
+ /**
47
+ * handle checkbox column
48
+ *
49
+ * @since 1.0.ß
50
+ * @see WP_List_Table::::single_row_columns()
51
+ * @param array $item A singular item (one full row's worth of data)
52
+ * @return string Text to be placed inside the column <td> (movie title only)
53
+ */
54
+ function column_cb($tag) {
55
+ $default_term = get_option('default_' . $this->screen->taxonomy);
56
+
57
+ return '<label class="screen-reader-text" for="cb-select-' . $tag->term_id . '">' . sprintf(__('Select %s', Advanced_Ads::TD), $tag->name) . '</label>'
58
+ . '<input type="checkbox" name="delete_tags[]" value="' . $tag->term_id . '" id="cb-select-' . $tag->term_id . '" />';
59
+
60
+ return '&nbsp;';
61
+ }
62
+
63
+ /**
64
+ * column with the ad group id
65
+ * @since 1.0.0
66
+ * @param type $tag
67
+ * @return string
68
+ */
69
+ function column_id($tag) {
70
+ return $tag->term_id;
71
+ }
72
+
73
+ /**
74
+ * render the basic ad group information
75
+ *
76
+ * @since 1.0.0
77
+ * @param obj $tag
78
+ * @return string
79
+ */
80
+ function column_name($tag) {
81
+ $tax = get_taxonomy($this->taxonomy);
82
+
83
+ $default_term = get_option('default_' . $this->taxonomy);
84
+
85
+ $name = apply_filters('term_name', $tag->name, $tag);
86
+ $qe_data = get_term($tag->term_id, $this->taxonomy, OBJECT, 'edit');
87
+ // $edit_link = esc_url(get_edit_term_link($tag->term_id, $this->taxonomy, $this->screen->post_type));
88
+ $args = array(
89
+ 'action' => 'edit',
90
+ 'group_id' => $tag->term_id
91
+ );
92
+ $edit_link = Advanced_Ads_Admin::group_page_url($args);
93
+
94
+ $out = '<strong><a class="row-title" href="' . $edit_link . '" title="' . esc_attr(sprintf(__('Edit &#8220;%s&#8221;', Advanced_Ads::TD), $name)) . '">' . $name . '</a></strong><br />';
95
+ $out .= '<p class="description">' . $tag->description . '</p>';
96
+
97
+ $actions = array();
98
+ if (current_user_can($tax->cap->edit_terms)) {
99
+ $actions['edit'] = '<a href="' . $edit_link . '">' . __('Edit', Advanced_Ads::TD) . '</a>';
100
+ // $actions['inline hide-if-no-js'] = '<a href="#" class="editinline">' . __('Quick&nbsp;Edit') . '</a>';
101
+ }
102
+ if (current_user_can($tax->cap->delete_terms) && $tag->term_id != $default_term){
103
+ $args = array(
104
+ 'action' => 'delete',
105
+ 'group_id' => $tag->term_id
106
+ );
107
+ $delete_link = Advanced_Ads_Admin::group_page_url($args);
108
+ $actions['delete'] = "<a class='delete-tag' href='" . wp_nonce_url($delete_link, 'delete-tag_' . $tag->term_id) . "'>" . __('Delete') . "</a>";
109
+ }
110
+
111
+ $actions = apply_filters("{$this->taxonomy}_row_actions", $actions, $tag);
112
+
113
+ $out .= $this->row_actions($actions);
114
+ $out .= '</div>';
115
+
116
+ return $out;
117
+ }
118
+
119
+ /**
120
+ * render the slug column
121
+ *
122
+ * @since 1.0.0
123
+ * @param obj $tag
124
+ * @return string
125
+ */
126
+ function column_slug($tag) {
127
+ return apply_filters('editable_slug', $tag->slug);
128
+ }
129
+
130
+ /**
131
+ * render the ads column (number of ads belonging to this group)
132
+ *
133
+ * @since 1.0.0
134
+ * @param obj $tag
135
+ * @return string
136
+ */
137
+ function column_ads($tag) {
138
+ $count = number_format_i18n($tag->count);
139
+
140
+ $tax = get_taxonomy($this->taxonomy);
141
+ $args = array(
142
+ 'post_type' => $this->post_type,
143
+ $this->taxonomy => $tag->slug
144
+ );
145
+ $ads = new WP_Query($args);
146
+
147
+ $group = new Advads_Ad_Group($tag->term_id);
148
+ $weights = $group->get_ad_weights();
149
+
150
+ $out = '';
151
+ $actions = array();
152
+ // The Loop
153
+ if ( $ads->have_posts() ) {
154
+ $out .= '<table class="advads-groups-ads-list">';
155
+ while ( $ads->have_posts() ) {
156
+ $ads->the_post();
157
+ $out .= '<tr><td><a href="' . get_edit_post_link(get_the_ID()) . '">' . get_the_title() . '</a>';
158
+ $_weight = (isset($weights[get_the_ID()])) ? $weights[get_the_ID()] : Advads_Ad_Group::MAX_AD_GROUP_WEIGHT;
159
+ $out .= '<td class="ad-weight ad-weight-' . get_the_ID() . '" title="'.__('Ad weight', Advanced_Ads::TD).'">' . $_weight . '</td></tr>';
160
+ $out .= '</tr>';
161
+ }
162
+ $out .= '</table>';
163
+ // include actions
164
+ $actions['edit'] = '<a href="#" class="edit-ad-group-ads">' . __('Edit', Advanced_Ads::TD) . '</a>';
165
+ $out .= $this->row_actions($actions);
166
+ // row with the group id
167
+ $out .= '<input type="hidden" class="ad-group-id" value="'. $tag->term_id .'"/>';
168
+ }
169
+ // Restore original Post Data
170
+ wp_reset_postdata();
171
+
172
+ return $out;
173
+ }
174
+
175
+ /**
176
+ * load the column names
177
+ *
178
+ * @since 1.0.0
179
+ * @see WP_List_Table::::single_row_columns()
180
+ * @return array An associative array containing column information: 'slugs'=>'Visible Titles'
181
+ * ************************************************************************ */
182
+ function get_columns() {
183
+ $columns = array(
184
+ // 'cb' => '<input type="checkbox" />', //Render a checkbox instead of text
185
+ 'id' => __('ID', $this->textdomain),
186
+ 'name' => __('Ad Group', $this->textdomain),
187
+ 'slug' => __('Slug', $this->textdomain),
188
+ 'ads' => __('Ads', $this->textdomain),
189
+ );
190
+ return $columns;
191
+ }
192
+
193
+ /**
194
+ * contains sortable columns
195
+ *
196
+ * @since 1.0.0
197
+ * @return array An associative array containing all the columns that should be sortable: 'slugs'=>array('data_values',bool)
198
+ * ************************************************************************ */
199
+ function get_sortable_columns() {
200
+ $sortable_columns = array(
201
+ 'id' => array('id', true), //true means it's already sorted
202
+ 'name' => array('name', false),
203
+ 'description' => array('description', false),
204
+ 'slug' => array('slug', false)
205
+ );
206
+ return $sortable_columns;
207
+ }
208
+
209
+ /**
210
+ * define bulk actions
211
+ *
212
+ * @since 1.0.0
213
+ * @return array An associative array containing all the bulk actions: 'slugs'=>'Visible Titles'
214
+ * ************************************************************************ */
215
+ function get_bulk_actions() {
216
+ $actions = array(
217
+ // 'delete' => __('Delete', $this->textdomain)
218
+ );
219
+ return $actions;
220
+ }
221
+
222
+ /**
223
+ * handle bulk actions here
224
+ *
225
+ * @since 1.0.0
226
+ * @see $this->prepare_items()
227
+ * ************************************************************************ */
228
+ function process_bulk_action() {
229
+
230
+ //Detect when a bulk action is being triggered...
231
+ if ('delete' === $this->current_action()) {
232
+
233
+ }
234
+ }
235
+
236
+ /**
237
+ * load items for output
238
+ *
239
+ * @since 1.0.0
240
+ */
241
+ function prepare_items() {
242
+ // how many items per page
243
+ // get_items_per_page basically uses a filter
244
+ $per_page = $this->get_items_per_page('edit_' . $this->taxonomy . '_per_page');
245
+
246
+ // set columns
247
+ $columns = $this->get_columns();
248
+ $hidden = array();
249
+ $sortable = $this->get_sortable_columns();
250
+
251
+ // combined array with all kinds of columns
252
+ $this->_column_headers = array($columns, $hidden, $sortable);
253
+
254
+ // process bulk actions
255
+ $this->process_bulk_action();
256
+
257
+ // prepare items
258
+ $search = !empty($_REQUEST['s']) ? trim(wp_unslash($_REQUEST['s'])) : '';
259
+
260
+ $args = array(
261
+ 'taxonomy' => $this->taxonomy,
262
+ 'search' => $search,
263
+ 'page' => $this->get_pagenum(),
264
+ 'number' => $per_page,
265
+ 'hide_empty' => 0,
266
+ 'orderby' => 'id'
267
+ );
268
+
269
+ if (!empty($_REQUEST['orderby']))
270
+ $args['orderby'] = trim(wp_unslash($_REQUEST['orderby']));
271
+
272
+ if (!empty($_REQUEST['order']))
273
+ $args['order'] = trim(wp_unslash($_REQUEST['order']));
274
+
275
+ $this->callback_args = $args;
276
+
277
+ // get items
278
+ $this->items = get_categories($args);
279
+
280
+ $total_items = count($this->items);
281
+ $this->set_pagination_args(array(
282
+ 'total_items' => $total_items,
283
+ 'per_page' => $per_page,
284
+ 'total_pages' => ceil($total_items / $per_page)
285
+ ));
286
+ }
287
+
288
+ }
admin/includes/class-list-table.php ADDED
@@ -0,0 +1,969 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Base class for displaying a list of items in an ajaxified HTML table.
4
+ *
5
+ * Derrived from WP_List_Table WordPress 3.9
6
+ * @link http://codex.wordpress.org/Class_Reference/WP_List_Table
7
+ *
8
+ * @package WordPress
9
+ * @subpackage List_Table
10
+ * @since 3.1.0
11
+ */
12
+
13
+ class AdvAds_List_Table {
14
+
15
+ /**
16
+ * The current list of items
17
+ *
18
+ * @since 3.1.0
19
+ * @var array
20
+ * @access protected
21
+ */
22
+ var $items;
23
+
24
+ /**
25
+ * Various information about the current table
26
+ *
27
+ * @since 3.1.0
28
+ * @var array
29
+ * @access private
30
+ */
31
+ var $_args;
32
+
33
+ /**
34
+ * Various information needed for displaying the pagination
35
+ *
36
+ * @since 3.1.0
37
+ * @var array
38
+ * @access private
39
+ */
40
+ var $_pagination_args = array();
41
+
42
+ /**
43
+ * The current screen
44
+ *
45
+ * @since 3.1.0
46
+ * @var object
47
+ * @access protected
48
+ */
49
+ var $screen;
50
+
51
+ /**
52
+ * Cached bulk actions
53
+ *
54
+ * @since 3.1.0
55
+ * @var array
56
+ * @access private
57
+ */
58
+ var $_actions;
59
+
60
+ /**
61
+ * Cached pagination output
62
+ *
63
+ * @since 3.1.0
64
+ * @var string
65
+ * @access private
66
+ */
67
+ var $_pagination;
68
+
69
+ /**
70
+ * Constructor. The child class should call this constructor from its own constructor
71
+ *
72
+ * @param array $args An associative array with information about the current table
73
+ * @access protected
74
+ */
75
+ function __construct( $args = array() ) {
76
+ $args = wp_parse_args( $args, array(
77
+ 'plural' => '',
78
+ 'singular' => '',
79
+ 'ajax' => false,
80
+ 'screen' => null,
81
+ ) );
82
+
83
+ $this->screen = convert_to_screen( $args['screen'] );
84
+
85
+ add_filter( "manage_{$this->screen->id}_columns", array( $this, 'get_columns' ), 0 );
86
+
87
+ if ( !$args['plural'] )
88
+ $args['plural'] = $this->screen->base;
89
+
90
+ $args['plural'] = sanitize_key( $args['plural'] );
91
+ $args['singular'] = sanitize_key( $args['singular'] );
92
+
93
+ $this->_args = $args;
94
+
95
+ if ( $args['ajax'] ) {
96
+ // wp_enqueue_script( 'list-table' );
97
+ add_action( 'admin_footer', array( $this, '_js_vars' ) );
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Checks the current user's permissions
103
+ * @uses wp_die()
104
+ *
105
+ * @since 3.1.0
106
+ * @access public
107
+ * @abstract
108
+ */
109
+ function ajax_user_can() {
110
+ die( 'function WP_List_Table::ajax_user_can() must be over-ridden in a sub-class.' );
111
+ }
112
+
113
+ /**
114
+ * Prepares the list of items for displaying.
115
+ * @uses WP_List_Table::set_pagination_args()
116
+ *
117
+ * @since 3.1.0
118
+ * @access public
119
+ * @abstract
120
+ */
121
+ function prepare_items() {
122
+ die( 'function WP_List_Table::prepare_items() must be over-ridden in a sub-class.' );
123
+ }
124
+
125
+ /**
126
+ * An internal method that sets all the necessary pagination arguments
127
+ *
128
+ * @param array $args An associative array with information about the pagination
129
+ * @access protected
130
+ */
131
+ function set_pagination_args( $args ) {
132
+ $args = wp_parse_args( $args, array(
133
+ 'total_items' => 0,
134
+ 'total_pages' => 0,
135
+ 'per_page' => 0,
136
+ ) );
137
+
138
+ if ( !$args['total_pages'] && $args['per_page'] > 0 )
139
+ $args['total_pages'] = ceil( $args['total_items'] / $args['per_page'] );
140
+
141
+ // redirect if page number is invalid and headers are not already sent
142
+ if ( ! headers_sent() && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) {
143
+ wp_redirect( add_query_arg( 'paged', $args['total_pages'] ) );
144
+ exit;
145
+ }
146
+
147
+ $this->_pagination_args = $args;
148
+ }
149
+
150
+ /**
151
+ * Access the pagination args
152
+ *
153
+ * @since 3.1.0
154
+ * @access public
155
+ *
156
+ * @param string $key
157
+ * @return array
158
+ */
159
+ function get_pagination_arg( $key ) {
160
+ if ( 'page' == $key )
161
+ return $this->get_pagenum();
162
+
163
+ if ( isset( $this->_pagination_args[$key] ) )
164
+ return $this->_pagination_args[$key];
165
+ }
166
+
167
+ /**
168
+ * Whether the table has items to display or not
169
+ *
170
+ * @since 3.1.0
171
+ * @access public
172
+ *
173
+ * @return bool
174
+ */
175
+ function has_items() {
176
+ return !empty( $this->items );
177
+ }
178
+
179
+ /**
180
+ * Message to be displayed when there are no items
181
+ *
182
+ * @since 3.1.0
183
+ * @access public
184
+ */
185
+ function no_items() {
186
+ _e( 'No items found.' );
187
+ }
188
+
189
+ /**
190
+ * Display the search box.
191
+ *
192
+ * @since 3.1.0
193
+ * @access public
194
+ *
195
+ * @param string $text The search button text
196
+ * @param string $input_id The search input id
197
+ */
198
+ function search_box( $text, $input_id ) {
199
+ if ( empty( $_REQUEST['s'] ) && !$this->has_items() )
200
+ return;
201
+
202
+ $input_id = $input_id . '-search-input';
203
+
204
+ if ( ! empty( $_REQUEST['orderby'] ) )
205
+ echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';
206
+ if ( ! empty( $_REQUEST['order'] ) )
207
+ echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
208
+ if ( ! empty( $_REQUEST['post_mime_type'] ) )
209
+ echo '<input type="hidden" name="post_mime_type" value="' . esc_attr( $_REQUEST['post_mime_type'] ) . '" />';
210
+ if ( ! empty( $_REQUEST['detached'] ) )
211
+ echo '<input type="hidden" name="detached" value="' . esc_attr( $_REQUEST['detached'] ) . '" />';
212
+ ?>
213
+ <p class="search-box">
214
+ <label class="screen-reader-text" for="<?php echo $input_id ?>"><?php echo $text; ?>:</label>
215
+ <input type="search" id="<?php echo $input_id ?>" name="s" value="<?php _admin_search_query(); ?>" />
216
+ <?php submit_button( $text, 'button', false, false, array('id' => 'search-submit') ); ?>
217
+ </p>
218
+ <?php
219
+ }
220
+
221
+ /**
222
+ * Get an associative array ( id => link ) with the list
223
+ * of views available on this table.
224
+ *
225
+ * @since 3.1.0
226
+ * @access protected
227
+ *
228
+ * @return array
229
+ */
230
+ function get_views() {
231
+ return array();
232
+ }
233
+
234
+ /**
235
+ * Display the list of views available on this table.
236
+ *
237
+ * @since 3.1.0
238
+ * @access public
239
+ */
240
+ function views() {
241
+ $views = $this->get_views();
242
+ /**
243
+ * Filter the list of available list table views.
244
+ *
245
+ * The dynamic portion of the hook name, $this->screen->id, refers
246
+ * to the ID of the current screen, usually a string.
247
+ *
248
+ * @since 3.5.0
249
+ *
250
+ * @param array $views An array of available list table views.
251
+ */
252
+ $views = apply_filters( "views_{$this->screen->id}", $views );
253
+
254
+ if ( empty( $views ) )
255
+ return;
256
+
257
+ echo "<ul class='subsubsub'>\n";
258
+ foreach ( $views as $class => $view ) {
259
+ $views[ $class ] = "\t<li class='$class'>$view";
260
+ }
261
+ echo implode( " |</li>\n", $views ) . "</li>\n";
262
+ echo "</ul>";
263
+ }
264
+
265
+ /**
266
+ * Get an associative array ( option_name => option_title ) with the list
267
+ * of bulk actions available on this table.
268
+ *
269
+ * @since 3.1.0
270
+ * @access protected
271
+ *
272
+ * @return array
273
+ */
274
+ function get_bulk_actions() {
275
+ return array();
276
+ }
277
+
278
+ /**
279
+ * Display the bulk actions dropdown.
280
+ *
281
+ * @since 3.1.0
282
+ * @access public
283
+ */
284
+ function bulk_actions() {
285
+ if ( is_null( $this->_actions ) ) {
286
+ $no_new_actions = $this->_actions = $this->get_bulk_actions();
287
+ /**
288
+ * Filter the list table Bulk Actions drop-down.
289
+ *
290
+ * The dynamic portion of the hook name, $this->screen->id, refers
291
+ * to the ID of the current screen, usually a string.
292
+ *
293
+ * This filter can currently only be used to remove bulk actions.
294
+ *
295
+ * @since 3.5.0
296
+ *
297
+ * @param array $actions An array of the available bulk actions.
298
+ */
299
+ $this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions );
300
+ $this->_actions = array_intersect_assoc( $this->_actions, $no_new_actions );
301
+ $two = '';
302
+ } else {
303
+ $two = '2';
304
+ }
305
+
306
+ if ( empty( $this->_actions ) )
307
+ return;
308
+
309
+ echo "<select name='action$two'>\n";
310
+ echo "<option value='-1' selected='selected'>" . __( 'Bulk Actions' ) . "</option>\n";
311
+
312
+ foreach ( $this->_actions as $name => $title ) {
313
+ $class = 'edit' == $name ? ' class="hide-if-no-js"' : '';
314
+
315
+ echo "\t<option value='$name'$class>$title</option>\n";
316
+ }
317
+
318
+ echo "</select>\n";
319
+
320
+ submit_button( __( 'Apply' ), 'action', false, false, array( 'id' => "doaction$two" ) );
321
+ echo "\n";
322
+ }
323
+
324
+ /**
325
+ * Get the current action selected from the bulk actions dropdown.
326
+ *
327
+ * @since 3.1.0
328
+ * @access public
329
+ *
330
+ * @return string|bool The action name or False if no action was selected
331
+ */
332
+ function current_action() {
333
+ if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] )
334
+ return $_REQUEST['action'];
335
+
336
+ if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] )
337
+ return $_REQUEST['action2'];
338
+
339
+ return false;
340
+ }
341
+
342
+ /**
343
+ * Generate row actions div
344
+ *
345
+ * @since 3.1.0
346
+ * @access protected
347
+ *
348
+ * @param array $actions The list of actions
349
+ * @param bool $always_visible Whether the actions should be always visible
350
+ * @return string
351
+ */
352
+ function row_actions( $actions, $always_visible = false ) {
353
+ $action_count = count( $actions );
354
+ $i = 0;
355
+
356
+ if ( !$action_count )
357
+ return '';
358
+
359
+ $out = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';
360
+ foreach ( $actions as $action => $link ) {
361
+ ++$i;
362
+ ( $i == $action_count ) ? $sep = '' : $sep = ' | ';
363
+ $out .= "<span class='$action'>$link$sep</span>";
364
+ }
365
+ $out .= '</div>';
366
+
367
+ return $out;
368
+ }
369
+
370
+ /**
371
+ * Display a monthly dropdown for filtering items
372
+ *
373
+ * @since 3.1.0
374
+ * @access protected
375
+ */
376
+ function months_dropdown( $post_type ) {
377
+ global $wpdb, $wp_locale;
378
+
379
+ $months = $wpdb->get_results( $wpdb->prepare( "
380
+ SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
381
+ FROM $wpdb->posts
382
+ WHERE post_type = %s
383
+ ORDER BY post_date DESC
384
+ ", $post_type ) );
385
+
386
+ /**
387
+ * Filter the 'Months' drop-down results.
388
+ *
389
+ * @since 3.7.0
390
+ *
391
+ * @param object $months The months drop-down query results.
392
+ * @param string $post_type The post type.
393
+ */
394
+ $months = apply_filters( 'months_dropdown_results', $months, $post_type );
395
+
396
+ $month_count = count( $months );
397
+
398
+ if ( !$month_count || ( 1 == $month_count && 0 == $months[0]->month ) )
399
+ return;
400
+
401
+ $m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
402
+ ?>
403
+ <select name='m'>
404
+ <option<?php selected( $m, 0 ); ?> value='0'><?php _e( 'Show all dates' ); ?></option>
405
+ <?php
406
+ foreach ( $months as $arc_row ) {
407
+ if ( 0 == $arc_row->year )
408
+ continue;
409
+
410
+ $month = zeroise( $arc_row->month, 2 );
411
+ $year = $arc_row->year;
412
+
413
+ printf( "<option %s value='%s'>%s</option>\n",
414
+ selected( $m, $year . $month, false ),
415
+ esc_attr( $arc_row->year . $month ),
416
+ /* translators: 1: month name, 2: 4-digit year */
417
+ sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month ), $year )
418
+ );
419
+ }
420
+ ?>
421
+ </select>
422
+ <?php
423
+ }
424
+
425
+ /**
426
+ * Display a view switcher
427
+ *
428
+ * @since 3.1.0
429
+ * @access protected
430
+ */
431
+ function view_switcher( $current_mode ) {
432
+ $modes = array(
433
+ 'list' => __( 'List View' ),
434
+ 'excerpt' => __( 'Excerpt View' )
435
+ );
436
+
437
+ ?>
438
+ <input type="hidden" name="mode" value="<?php echo esc_attr( $current_mode ); ?>" />
439
+ <div class="view-switch">
440
+ <?php
441
+ foreach ( $modes as $mode => $title ) {
442
+ $class = ( $current_mode == $mode ) ? 'class="current"' : '';
443
+ echo "<a href='" . esc_url( add_query_arg( 'mode', $mode, $_SERVER['REQUEST_URI'] ) ) . "' $class><img id='view-switch-$mode' src='" . esc_url( includes_url( 'images/blank.gif' ) ) . "' width='20' height='20' title='$title' alt='$title' /></a>\n";
444
+ }
445
+ ?>
446
+ </div>
447
+ <?php
448
+ }
449
+
450
+ /**
451
+ * Display a comment count bubble
452
+ *
453
+ * @since 3.1.0
454
+ * @access protected
455
+ *
456
+ * @param int $post_id
457
+ * @param int $pending_comments
458
+ */
459
+ function comments_bubble( $post_id, $pending_comments ) {
460
+ $pending_phrase = sprintf( __( '%s pending' ), number_format( $pending_comments ) );
461
+
462
+ if ( $pending_comments )
463
+ echo '<strong>';
464
+
465
+ echo "<a href='" . esc_url( add_query_arg( 'p', $post_id, admin_url( 'edit-comments.php' ) ) ) . "' title='" . esc_attr( $pending_phrase ) . "' class='post-com-count'><span class='comment-count'>" . number_format_i18n( get_comments_number() ) . "</span></a>";
466
+
467
+ if ( $pending_comments )
468
+ echo '</strong>';
469
+ }
470
+
471
+ /**
472
+ * Get the current page number
473
+ *
474
+ * @since 3.1.0
475
+ * @access protected
476
+ *
477
+ * @return int
478
+ */
479
+ function get_pagenum() {
480
+ $pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0;
481
+
482
+ if( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] )
483
+ $pagenum = $this->_pagination_args['total_pages'];
484
+
485
+ return max( 1, $pagenum );
486
+ }
487
+
488
+ /**
489
+ * Get number of items to display on a single page
490
+ *
491
+ * @since 3.1.0
492
+ * @access protected
493
+ *
494
+ * @return int
495
+ */
496
+ function get_items_per_page( $option, $default = 20 ) {
497
+ $per_page = (int) get_user_option( $option );
498
+ if ( empty( $per_page ) || $per_page < 1 )
499
+ $per_page = $default;
500
+
501
+ /**
502
+ * Filter the number of items to be displayed on each page of the list table.
503
+ *
504
+ * The dynamic hook name, $option, refers to the per page option depending
505
+ * on the type of list table in use. Possible values may include:
506
+ * 'edit_comments_per_page', 'sites_network_per_page', 'site_themes_network_per_page',
507
+ * 'themes_netework_per_page', 'users_network_per_page', 'edit_{$post_type}', etc.
508
+ *
509
+ * @since 2.9.0
510
+ *
511
+ * @param int $per_page Number of items to be displayed. Default 20.
512
+ */
513
+ return (int) apply_filters( $option, $per_page );
514
+ }
515
+
516
+ /**
517
+ * Display the pagination.
518
+ *
519
+ * @since 3.1.0
520
+ * @access protected
521
+ */
522
+ function pagination( $which ) {
523
+ if ( empty( $this->_pagination_args ) )
524
+ return;
525
+
526
+ extract( $this->_pagination_args, EXTR_SKIP );
527
+
528
+ $output = '<span class="displaying-num">' . sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>';
529
+
530
+ $current = $this->get_pagenum();
531
+
532
+ $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
533
+
534
+ $current_url = remove_query_arg( array( 'hotkeys_highlight_last', 'hotkeys_highlight_first' ), $current_url );
535
+
536
+ $page_links = array();
537
+
538
+ $disable_first = $disable_last = '';
539
+ if ( $current == 1 )
540
+ $disable_first = ' disabled';
541
+ if ( $current == $total_pages )
542
+ $disable_last = ' disabled';
543
+
544
+ $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
545
+ 'first-page' . $disable_first,
546
+ esc_attr__( 'Go to the first page' ),
547
+ esc_url( remove_query_arg( 'paged', $current_url ) ),
548
+ '&laquo;'
549
+ );
550
+
551
+ $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
552
+ 'prev-page' . $disable_first,
553
+ esc_attr__( 'Go to the previous page' ),
554
+ esc_url( add_query_arg( 'paged', max( 1, $current-1 ), $current_url ) ),
555
+ '&lsaquo;'
556
+ );
557
+
558
+ if ( 'bottom' == $which )
559
+ $html_current_page = $current;
560
+ else
561
+ $html_current_page = sprintf( "<input class='current-page' title='%s' type='text' name='paged' value='%s' size='%d' />",
562
+ esc_attr__( 'Current page' ),
563
+ $current,
564
+ strlen( $total_pages )
565
+ );
566
+
567
+ $html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
568
+ $page_links[] = '<span class="paging-input">' . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . '</span>';
569
+
570
+ $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
571
+ 'next-page' . $disable_last,
572
+ esc_attr__( 'Go to the next page' ),
573
+ esc_url( add_query_arg( 'paged', min( $total_pages, $current+1 ), $current_url ) ),
574
+ '&rsaquo;'
575
+ );
576
+
577
+ $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
578
+ 'last-page' . $disable_last,
579
+ esc_attr__( 'Go to the last page' ),
580
+ esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
581
+ '&raquo;'
582
+ );
583
+
584
+ $pagination_links_class = 'pagination-links';
585
+ if ( ! empty( $infinite_scroll ) )
586
+ $pagination_links_class = ' hide-if-js';
587
+ $output .= "\n<span class='$pagination_links_class'>" . join( "\n", $page_links ) . '</span>';
588
+
589
+ if ( $total_pages )
590
+ $page_class = $total_pages < 2 ? ' one-page' : '';
591
+ else
592
+ $page_class = ' no-pages';
593
+
594
+ $this->_pagination = "<div class='tablenav-pages{$page_class}'>$output</div>";
595
+
596
+ echo $this->_pagination;
597
+ }
598
+
599
+ /**
600
+ * Get a list of columns. The format is:
601
+ * 'internal-name' => 'Title'
602
+ *
603
+ * @since 3.1.0
604
+ * @access protected
605
+ * @abstract
606
+ *
607
+ * @return array
608
+ */
609
+ function get_columns() {
610
+ die( 'function WP_List_Table::get_columns() must be over-ridden in a sub-class.' );
611
+ }
612
+
613
+ /**
614
+ * Get a list of sortable columns. The format is:
615
+ * 'internal-name' => 'orderby'
616
+ * or
617
+ * 'internal-name' => array( 'orderby', true )
618
+ *
619
+ * The second format will make the initial sorting order be descending
620
+ *
621
+ * @since 3.1.0
622
+ * @access protected
623
+ *
624
+ * @return array
625
+ */
626
+ function get_sortable_columns() {
627
+ return array();
628
+ }
629
+
630
+ /**
631
+ * Get a list of all, hidden and sortable columns, with filter applied
632
+ *
633
+ * @since 3.1.0
634
+ * @access protected
635
+ *
636
+ * @return array
637
+ */
638
+ function get_column_info() {
639
+ if ( isset( $this->_column_headers ) )
640
+ return $this->_column_headers;
641
+
642
+ $columns = get_column_headers( $this->screen );
643
+ $hidden = get_hidden_columns( $this->screen );
644
+
645
+ $sortable_columns = $this->get_sortable_columns();
646
+ /**
647
+ * Filter the list table sortable columns for a specific screen.
648
+ *
649
+ * The dynamic portion of the hook name, $this->screen->id, refers
650
+ * to the ID of the current screen, usually a string.
651
+ *
652
+ * @since 3.5.0
653
+ *
654
+ * @param array $sortable_columns An array of sortable columns.
655
+ */
656
+ $_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $sortable_columns );
657
+
658
+ $sortable = array();
659
+ foreach ( $_sortable as $id => $data ) {
660
+ if ( empty( $data ) )
661
+ continue;
662
+
663
+ $data = (array) $data;
664
+ if ( !isset( $data[1] ) )
665
+ $data[1] = false;
666
+
667
+ $sortable[$id] = $data;
668
+ }
669
+
670
+ $this->_column_headers = array( $columns, $hidden, $sortable );
671
+
672
+ return $this->_column_headers;
673
+ }
674
+
675
+ /**
676
+ * Return number of visible columns
677
+ *
678
+ * @since 3.1.0
679
+ * @access public
680
+ *
681
+ * @return int
682
+ */
683
+ function get_column_count() {
684
+ list ( $columns, $hidden ) = $this->get_column_info();
685
+ $hidden = array_intersect( array_keys( $columns ), array_filter( $hidden ) );
686
+ return count( $columns ) - count( $hidden );
687
+ }
688
+
689
+ /**
690
+ * Print column headers, accounting for hidden and sortable columns.
691
+ *
692
+ * @since 3.1.0
693
+ * @access protected
694
+ *
695
+ * @param bool $with_id Whether to set the id attribute or not
696
+ */
697
+ function print_column_headers( $with_id = true ) {
698
+ list( $columns, $hidden, $sortable ) = $this->get_column_info();
699
+
700
+ $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
701
+ $current_url = remove_query_arg( 'paged', $current_url );
702
+
703
+ if ( isset( $_GET['orderby'] ) )
704
+ $current_orderby = $_GET['orderby'];
705
+ else
706
+ $current_orderby = '';
707
+
708
+ if ( isset( $_GET['order'] ) && 'desc' == $_GET['order'] )
709
+ $current_order = 'desc';
710
+ else
711
+ $current_order = 'asc';
712
+
713
+ if ( ! empty( $columns['cb'] ) ) {
714
+ static $cb_counter = 1;
715
+ $columns['cb'] = '<label class="screen-reader-text" for="cb-select-all-' . $cb_counter . '">' . __( 'Select All' ) . '</label>'
716
+ . '<input id="cb-select-all-' . $cb_counter . '" type="checkbox" />';
717
+ $cb_counter++;
718
+ }
719
+
720
+ foreach ( $columns as $column_key => $column_display_name ) {
721
+ $class = array( 'manage-column', "column-$column_key" );
722
+
723
+ $style = '';
724
+ if ( in_array( $column_key, $hidden ) )
725
+ $style = 'display:none;';
726
+
727
+ $style = ' style="' . $style . '"';
728
+
729
+ if ( 'cb' == $column_key )
730
+ $class[] = 'check-column';
731
+ elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) )
732
+ $class[] = 'num';
733
+
734
+ if ( isset( $sortable[$column_key] ) ) {
735
+ list( $orderby, $desc_first ) = $sortable[$column_key];
736
+
737
+ if ( $current_orderby == $orderby ) {
738
+ $order = 'asc' == $current_order ? 'desc' : 'asc';
739
+ $class[] = 'sorted';
740
+ $class[] = $current_order;
741
+ } else {
742
+ $order = $desc_first ? 'desc' : 'asc';
743
+ $class[] = 'sortable';
744
+ $class[] = $desc_first ? 'asc' : 'desc';
745
+ }
746
+
747
+ $column_display_name = '<a href="' . esc_url( add_query_arg( compact( 'orderby', 'order' ), $current_url ) ) . '"><span>' . $column_display_name . '</span><span class="sorting-indicator"></span></a>';
748
+ }
749
+
750
+ $id = $with_id ? "id='$column_key'" : '';
751
+
752
+ if ( !empty( $class ) )
753
+ $class = "class='" . join( ' ', $class ) . "'";
754
+
755
+ echo "<th scope='col' $id $class $style>$column_display_name</th>";
756
+ }
757
+ }
758
+
759
+ /**
760
+ * Display the table
761
+ *
762
+ * @since 3.1.0
763
+ * @access public
764
+ */
765
+ function display() {
766
+ extract( $this->_args );
767
+
768
+ $this->display_tablenav( 'top' );
769
+
770
+ ?>
771
+ <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>" cellspacing="0">
772
+ <thead>
773
+ <tr>
774
+ <?php $this->print_column_headers(); ?>
775
+ </tr>
776
+ </thead>
777
+
778
+ <tfoot>
779
+ <tr>
780
+ <?php $this->print_column_headers( false ); ?>
781
+ </tr>
782
+ </tfoot>
783
+
784
+ <tbody id="the-list"<?php if ( $singular ) echo " data-wp-lists='list:$singular'"; ?>>
785
+ <?php $this->display_rows_or_placeholder(); ?>
786
+ </tbody>
787
+ </table>
788
+ <?php
789
+ $this->display_tablenav( 'bottom' );
790
+ }
791
+
792
+ /**
793
+ * Get a list of CSS classes for the <table> tag
794
+ *
795
+ * @since 3.1.0
796
+ * @access protected
797
+ *
798
+ * @return array
799
+ */
800
+ function get_table_classes() {
801
+ return array( 'widefat', 'fixed', $this->_args['plural'] );
802
+ }
803
+
804
+ /**
805
+ * Generate the table navigation above or below the table
806
+ *
807
+ * @since 3.1.0
808
+ * @access protected
809
+ */
810
+ function display_tablenav( $which ) {
811
+ if ( 'top' == $which )
812
+ wp_nonce_field( 'bulk-' . $this->_args['plural'] );
813
+ ?>
814
+ <div class="tablenav <?php echo esc_attr( $which ); ?>">
815
+
816
+ <div class="alignleft actions bulkactions">
817
+ <?php $this->bulk_actions(); ?>
818
+ </div>
819
+ <?php
820
+ $this->extra_tablenav( $which );
821
+ $this->pagination( $which );
822
+ ?>
823
+
824
+ <br class="clear" />
825
+ </div>
826
+ <?php
827
+ }
828
+
829
+ /**
830
+ * Extra controls to be displayed between bulk actions and pagination
831
+ *
832
+ * @since 3.1.0
833
+ * @access protected
834
+ */
835
+ function extra_tablenav( $which ) {}
836
+
837
+ /**
838
+ * Generate the <tbody> part of the table
839
+ *
840
+ * @since 3.1.0
841
+ * @access protected
842
+ */
843
+ function display_rows_or_placeholder() {
844
+ if ( $this->has_items() ) {
845
+ $this->display_rows();
846
+ } else {
847
+ list( $columns, $hidden ) = $this->get_column_info();
848
+ echo '<tr class="no-items"><td class="colspanchange" colspan="' . $this->get_column_count() . '">';
849
+ $this->no_items();
850
+ echo '</td></tr>';
851
+ }
852
+ }
853
+
854
+ /**
855
+ * Generate the table rows
856
+ *
857
+ * @since 3.1.0
858
+ * @access protected
859
+ */
860
+ function display_rows() {
861
+ foreach ( $this->items as $item )
862
+ $this->single_row( $item );
863
+ }
864
+
865
+ /**
866
+ * Generates content for a single row of the table
867
+ *
868
+ * @since 3.1.0
869
+ * @access protected
870
+ *
871
+ * @param object $item The current item
872
+ */
873
+ function single_row( $item ) {
874
+ static $row_class = '';
875
+ $row_class = ( $row_class == '' ? ' class="alternate"' : '' );
876
+
877
+ echo '<tr' . $row_class . '>';
878
+ $this->single_row_columns( $item );
879
+ echo '</tr>';
880
+ }
881
+
882
+ /**
883
+ * Generates the columns for a single row of the table
884
+ *
885
+ * @since 3.1.0
886
+ * @access protected
887
+ *
888
+ * @param object $item The current item
889
+ */
890
+ function single_row_columns( $item ) {
891
+ list( $columns, $hidden ) = $this->get_column_info();
892
+
893
+ foreach ( $columns as $column_name => $column_display_name ) {
894
+ $class = "class='$column_name column-$column_name'";
895
+
896
+ $style = '';
897
+ if ( in_array( $column_name, $hidden ) )
898
+ $style = ' style="display:none;"';
899
+
900
+ $attributes = "$class$style";
901
+
902
+ if ( 'cb' == $column_name ) {
903
+ echo '<th scope="row" class="check-column">';
904
+ echo $this->column_cb( $item );
905
+ echo '</th>';
906
+ }
907
+ elseif ( method_exists( $this, 'column_' . $column_name ) ) {
908
+ echo "<td $attributes>";
909
+ echo call_user_func( array( $this, 'column_' . $column_name ), $item );
910
+ echo "</td>";
911
+ }
912
+ else {
913
+ echo "<td $attributes>";
914
+ echo $this->column_default( $item, $column_name );
915
+ echo "</td>";
916
+ }
917
+ }
918
+ }
919
+
920
+ /**
921
+ * Handle an incoming ajax request (called from admin-ajax.php)
922
+ *
923
+ * @since 3.1.0
924
+ * @access public
925
+ */
926
+ function ajax_response() {
927
+ $this->prepare_items();
928
+
929
+ extract( $this->_args );
930
+ extract( $this->_pagination_args, EXTR_SKIP );
931
+
932
+ ob_start();
933
+ if ( ! empty( $_REQUEST['no_placeholder'] ) )
934
+ $this->display_rows();
935
+ else
936
+ $this->display_rows_or_placeholder();
937
+
938
+ $rows = ob_get_clean();
939
+
940
+ $response = array( 'rows' => $rows );
941
+
942
+ if ( isset( $total_items ) )
943
+ $response['total_items_i18n'] = sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) );
944
+
945
+ if ( isset( $total_pages ) ) {
946
+ $response['total_pages'] = $total_pages;
947
+ $response['total_pages_i18n'] = number_format_i18n( $total_pages );
948
+ }
949
+
950
+ die( json_encode( $response ) );
951
+ }
952
+
953
+ /**
954
+ * Send required variables to JavaScript land
955
+ *
956
+ * @access private
957
+ */
958
+ function _js_vars() {
959
+ $args = array(
960
+ 'class' => get_class( $this ),
961
+ 'screen' => array(
962
+ 'id' => $this->screen->id,
963
+ 'base' => $this->screen->base,
964
+ )
965
+ );
966
+
967
+ printf( "<script type='text/javascript'>list_args = %s;</script>\n", json_encode( $args ) );
968
+ }
969
+ }
admin/includes/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php // Silence is golden
admin/views/ad-display-metabox.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php $types = Advanced_Ads::get_instance()->ad_types; ?>
2
+ <h4><?php _e('Where to display the ad', $this->plugin_slug); ?></h4>
3
+ <p class="advads-toggle-link" onclick="advads_toggle('#advads-how-it-works')">>>><?php _e('Click to see Help', $this->plugin_slug); ?><<<</p>
4
+ <ul id="advads-how-it-works" style="display: none;">
5
+ <li><?php _e('If you want to display the ad everywhere, don’t do anything here. ', $this->plugin_slug); ?></li>
6
+ <li><?php _e('The fewer conditions you enter, the better the performance will be.', $this->plugin_slug); ?></li>
7
+ <li><?php _e('Filling more than one item into the ’show here’ text field means at least one of them needs to be true. (OR)', $this->plugin_slug); ?></li>
8
+ <li><?php _e('Filling more than one item into the ’don’t show’ text field means all must match (AND).', $this->plugin_slug); ?></li>
9
+ <li><?php _e('When using one of the two choices on checkbox conditions, the rule is binding. E.g. "Front Page: show here" will result on the ad being only visible on the front page.', $this->plugin_slug); ?></li>
10
+ <li><?php _e('If there is nothing in the row, there won’t be any check. Meaning, if you leave everything empty, the ad will be displayed everywhere.', $this->plugin_slug); ?></li>
11
+ </ul>
12
+ <table id="advanced-ad-conditions">
13
+ <thead>
14
+ <tr>
15
+ <th></th>
16
+ <th><?php _e('show here', $this->plugin_slug); ?></th>
17
+ <th><?php _e('DON’T show', $this->plugin_slug); ?></th>
18
+ <th></th>
19
+ </tr>
20
+ <?php global $advanced_ads_ad_conditions;
21
+ if (is_array($advanced_ads_ad_conditions))
22
+ foreach ($advanced_ads_ad_conditions as $_key => $_condition) :
23
+ ?><tr>
24
+ <th><?php echo $_condition['label']; ?>
25
+ <?php if (!empty($_condition['description'])) : ?>
26
+ <span class="description" title="<?php echo $_condition['description']; ?>">(?)</span>
27
+ <?php endif; ?>
28
+ </th>
29
+ <?php if (empty($_condition['type'])) : continue; ?>
30
+ <?php elseif ($_condition['type'] == 'idfield' || $_condition['type'] == 'textvalues') : ?>
31
+ <td><input type="text" name="advanced_ad[conditions][<?php echo $_key; ?>][include]" value="<?php if(isset($ad->conditions[$_key]['include'])) echo $ad->conditions[$_key]['include']; ?>"/></td>
32
+ <td><input type="text" name="advanced_ad[conditions][<?php echo $_key; ?>][exclude]" value="<?php if(isset($ad->conditions[$_key]['exclude'])) echo $ad->conditions[$_key]['exclude']; ?>"/></td>
33
+ <?php elseif ($_condition['type'] == 'radio') : ?>
34
+ <td><input type="radio" name="advanced_ad[conditions][<?php echo $_key; ?>]" value="1" <?php if(isset($ad->conditions[$_key])) checked($ad->conditions[$_key], 1) ?>/></td>
35
+ <td><input type="radio" name="advanced_ad[conditions][<?php echo $_key; ?>]" value="0" <?php if(isset($ad->conditions[$_key])) checked($ad->conditions[$_key], 0) ?>/></td>
36
+ <?php endif; ?>
37
+ <td><button type="button" class="clear-radio"><?php _e('clear', $this->plugin_slug); ?></button></td>
38
+ </tr>
39
+ <?php endforeach; ?>
40
+ </thead>
41
+ </table>
admin/views/ad-group-ads-inline-form.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if(count($ads)) : ?>
2
+ <form method="get" action="" class="ad-group-ads-form">
3
+ <table>
4
+ <tbody>
5
+ <?php foreach($ads as $_ad) : ?>
6
+ <tr>
7
+ <td><?php echo $_ad->post_title; ?></td>
8
+ <td class="ad-group-ads-weight">
9
+ <label>
10
+ <span class="title"><?php _ex('weight', 'ad group ads form', Advanced_Ads::TD); ?></span>
11
+ <select name="weight[<?php echo $_ad->ID; ?>]">
12
+ <?php $ad_weight = (isset($weights[$_ad->ID])) ? $weights[$_ad->ID] : Advads_Ad_Group::MAX_AD_GROUP_WEIGHT; ?>
13
+ <? for($i = 0; $i <= Advads_Ad_Group::MAX_AD_GROUP_WEIGHT; $i++) : ?>
14
+ <option <?php selected($ad_weight, $i); ?>><?php echo $i; ?></option>
15
+ <? endfor; ?>
16
+ </select>
17
+ </label>
18
+ </td>
19
+ </tr>
20
+ <?php endforeach; ?>
21
+ </tbody>
22
+ </table>
23
+ <p class="inline-edit-save submit">
24
+ <a href="#inline-edit" class="cancel button-secondary alignleft"><?php _e('Cancel', Advanced_Ads::TD); ?></a>
25
+ <a href="#inline-edit" class="save button-primary alignright"><?php _e('Update', Advanced_Ads::TD); ?></a>
26
+ <span class="spinner"></span>
27
+ <?php wp_nonce_field('ad-groups-inline-edit-nonce', 'advads-ad-groups-inline-form-nonce', false); ?>
28
+ <input type="hidden" name="taxonomy" value="<?php echo $group->id; ?>" />
29
+ <br class="clear" />
30
+ </p>
31
+ </form>
32
+ <?php else : ?>
33
+ <p><?php _e('There are no ads in this group', Advanced_Ads::plugin_slug); ?>
34
+ <?php endif; ?>
admin/views/ad-group-edit.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Create and edit ad group form
4
+ *
5
+ * @package WordPress
6
+ * @subpackage Administration
7
+ */
8
+ // don't load directly
9
+ if (!defined('ABSPATH'))
10
+ die('-1');
11
+
12
+ if (!is_int($group_id)) {
13
+ ?>
14
+ <div id="message" class="updated"><p><strong><?php _e('You did not select an item for editing.'); ?></strong></p></div>
15
+ <?php
16
+ return;
17
+ }
18
+
19
+ do_action("{$taxonomy}_pre_edit_form", $tag, $taxonomy);
20
+ ?>
21
+
22
+ <div class="wrap">
23
+ <h2><?php echo $tax->labels->edit_item; ?></h2>
24
+ <div id="ajax-response"></div>
25
+ <form name="editgroup" id="editgroup" method="post" action="<?php echo Advanced_Ads_Admin::group_page_url(); ?>" class="validate"<?php do_action($taxonomy . '_term_edit_form_tag'); ?>>
26
+ <input type="hidden" name="action" value="editedgroup" />
27
+ <input type="hidden" name="group_id" value="<?php echo $group_id; ?>" />
28
+ <input type="hidden" name="taxonomy" value="<?php echo esc_attr($taxonomy) ?>" />
29
+ <?php wp_original_referer_field(true, 'previous');
30
+ wp_nonce_field('update-group_' . $group_id); ?>
31
+ <table class="form-table">
32
+ <tr class="form-field form-required">
33
+ <th scope="row" valign="top"><label for="name"><?php _ex('Name', 'Taxonomy Name'); ?></label></th>
34
+ <td><input name="name" id="name" type="text" value="<?php if (isset($tag->name)) echo esc_attr($tag->name); ?>" size="40" aria-required="true" /></td>
35
+ </tr>
36
+ <?php if (!global_terms_enabled()) { ?>
37
+ <tr class="form-field">
38
+ <th scope="row" valign="top"><label for="slug"><?php _ex('Slug', 'Taxonomy Slug'); ?></label></th>
39
+ <td><input name="slug" id="slug" type="text" value="<?php if (isset($tag->slug)) echo esc_attr(apply_filters('editable_slug', $tag->slug)); ?>" size="40" />
40
+ <p class="description"><?php _e('An id-like string with only letters in lower case, numbers, and hyphens. Can be used to query a group.', $this->plugin_slug); ?></p></td>
41
+ </tr>
42
+ <?php } ?>
43
+ <?php if (is_taxonomy_hierarchical($taxonomy)) : ?>
44
+ <tr class="form-field">
45
+ <th scope="row" valign="top"><label for="parent"><?php _ex('Parent', 'Taxonomy Parent'); ?></label></th>
46
+ <td>
47
+ <?php if($group_id == 0){
48
+ wp_dropdown_categories(array('hide_empty' => 0, 'hide_if_empty' => false, 'name' => 'parent', 'orderby' => 'name', 'taxonomy' => $taxonomy, 'hierarchical' => true, 'show_option_none' => __('None')));
49
+ } else {
50
+ wp_dropdown_categories(array('hide_empty' => 0, 'hide_if_empty' => false, 'name' => 'parent', 'orderby' => 'name', 'taxonomy' => $taxonomy, 'selected' => $tag->parent, 'exclude_tree' => $tag->term_id, 'hierarchical' => true, 'show_option_none' => __('None')));
51
+ }; ?></td>
52
+ </tr>
53
+ <?php endif; // is_taxonomy_hierarchical()
54
+ $text = (isset($tag->description)) ? $tag->description : ''; ?>
55
+ <tr class="form-field">
56
+ <th scope="row" valign="top"><label for="description"><?php _ex('Description', 'Taxonomy Description'); ?></label></th>
57
+ <td><textarea name="description" id="description" rows="5" cols="50" class="large-text"><?php echo $text; // textarea_escaped ?></textarea></td>
58
+ </tr>
59
+ <?php
60
+
61
+ do_action($taxonomy . '_edit_form_fields', $tag, $taxonomy);
62
+ ?>
63
+ </table>
64
+ <?php
65
+ do_action($taxonomy . '_edit_form', $tag, $taxonomy);
66
+
67
+ if($group_id == 0){
68
+ submit_button(__('Create new Ad Group', $this->plugin_slug));
69
+ } else {
70
+ submit_button(__('Update', $this->plugin_slug));
71
+ }
72
+ ?>
73
+ </form>
74
+ </div>
75
+ <script type="text/javascript">
76
+ try {
77
+ document.forms.edittag.name.focus();
78
+ } catch (e) {
79
+ }
80
+ </script>
admin/views/ad-group.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * page lists ad groups
4
+ *
5
+ * @since 1.0.0
6
+ * @see /wp-admin/edit-tags.php (for a good example in WP core)
7
+ */
8
+ $ad_group_table = new AdvAds_Groups_List_Table(array('screen' => get_current_screen()));
9
+ $ad_group_table->textdomain = $this->plugin_slug;
10
+ $pagenum = $ad_group_table->get_pagenum();
11
+
12
+ $ad_group_table->prepare_items();
13
+ $total_pages = $ad_group_table->get_pagination_arg('total_pages');
14
+
15
+ if ($pagenum > $total_pages && $total_pages > 0) {
16
+ wp_redirect(add_query_arg('paged', $total_pages));
17
+ exit;
18
+ }
19
+
20
+ /**
21
+ * @TODO those 2 scripts needed? or even extend it with our own?
22
+ */
23
+ // wp_enqueue_script('admin-tags');
24
+
25
+ if (current_user_can($tax->cap->edit_terms)) {
26
+ wp_enqueue_script('inline-edit-group-ads');
27
+ }
28
+
29
+ // require_once( ABSPATH . 'wp-admin/admin-header.php' );
30
+
31
+ $messages[$taxonomy] = array(
32
+ 0 => '', // Unused. Messages start at index 1.
33
+ 1 => __('Ad Group added.', $this->plugin_slug),
34
+ 2 => __('Ad Group deleted.', $this->plugin_slug),
35
+ 3 => __('Ad Group updated.', $this->plugin_slug),
36
+ 4 => __('Ad Group not added.', $this->plugin_slug),
37
+ 5 => __('Ad Group not updated.', $this->plugin_slug),
38
+ 6 => __('Ad Group deleted.', $this->plugin_slug)
39
+ );
40
+
41
+ $message = false;
42
+ if (isset($_REQUEST['message']) && ( $msg = (int) $_REQUEST['message'] ) || isset($forced_message)) {
43
+ if (isset($msg) && isset($messages[$taxonomy][$msg])){
44
+ $message = $messages[$taxonomy][$msg];
45
+ } elseif(isset($messages[$taxonomy][$forced_message])) {
46
+ $message = $messages[$taxonomy][$forced_message];
47
+ }
48
+ }
49
+ ?>
50
+
51
+ <div class="wrap nosubsub">
52
+ <h2><?php
53
+ echo esc_html($title);
54
+ if (!empty($_REQUEST['s'])) {
55
+ printf('<span class="subtitle">' . __('Search results for &#8220;%s&#8221;', $this->plugin_slug) . '</span>', esc_html(wp_unslash($_REQUEST['s'])));
56
+ } else {
57
+ echo ' <a href="' . Advanced_Ads_Admin::group_page_url(array('action' => 'edit')) . '" class="add-new-h2">' . $tax->labels->add_new_item . '</a>';
58
+ }
59
+ ?>
60
+ </h2>
61
+
62
+ <?php if ($message) : ?>
63
+ <div id="message" class="updated"><p><?php echo $message; ?></p></div>
64
+ <?php
65
+ $_SERVER['REQUEST_URI'] = remove_query_arg(array('message'), $_SERVER['REQUEST_URI']);
66
+ endif;
67
+ ?>
68
+ <div id="ajax-response"></div>
69
+
70
+ <div id="col-container">
71
+ <div class="col-wrap">
72
+ <form class="search-form" action="" method="get">
73
+ <!--input type="hidden" name="taxonomy" value="<?php echo esc_attr($taxonomy); ?>" /-->
74
+ <input type="hidden" name="page" value="advanced-ads-groups" />
75
+ <input type="hidden" name="post_type" value="<?php echo esc_attr($post_type); ?>" />
76
+ <?php $ad_group_table->search_box($tax->labels->search_items, 'tag'); ?>
77
+
78
+ </form>
79
+ <br class="clear" />
80
+ <form id="posts-filter" action="" method="post">
81
+ <input type="hidden" name="taxonomy" value="<?php echo esc_attr($taxonomy); ?>" />
82
+ <input type="hidden" name="post_type" value="<?php echo esc_attr($post_type); ?>" />
83
+
84
+ <?php $ad_group_table->display(); ?>
85
+
86
+ <br class="clear" />
87
+ </form><?php
88
+ /**
89
+ * Fires after the ad grouptable.
90
+ *
91
+ * The dynamic portion of the hook name, $taxonomy, refers to the taxonomy slug.
92
+ *
93
+ * @since 1.0.0
94
+ * @param string $taxonomy The taxonomy name.
95
+ */
96
+ do_action("after-{$taxonomy}-table", $taxonomy);
97
+ ?>
98
+
99
+ </div>
100
+ </div><!-- /col-container -->
101
+ </div><!-- /wrap -->
admin/views/ad-main-metabox.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php $types = Advanced_Ads::get_instance()->ad_types; ?>
2
+ <?php if (empty($types)) : ?>
3
+ <p><?php _e('No ad types defined', $this->plugin_slug); ?></p>
4
+ <?php else : ?>
5
+ <h4><?php _e('Ad Type and Content', $this->plugin_slug); ?></h4>
6
+ <ul id="advanced-ad-type">
7
+ <?php
8
+ // choose first type if none set
9
+ $type = (isset($ad->type)) ? $ad->type : current($types)->ID;
10
+ foreach ($types as $_type) : ?>
11
+ <li>
12
+ <input type="radio" name="advanced_ad[type]"
13
+ id="advanced-ad-type-<?php echo $_type->ID ?>"
14
+ value="<?php echo $_type->ID; ?>"
15
+ <?php checked($type, $_type->ID); ?>/>
16
+ <label for="advanced-ad-type-<?php echo $_type->ID ?>"><?php echo (empty($_type->title)) ? $_type->ID : $_type->title; ?></label>
17
+ <?php if (!empty($_type->description)) : ?><span class="description"><?php echo $_type->description; ?></span><?php endif; ?>
18
+ </li>
19
+ <?php endforeach; ?>
20
+ </ul>
21
+ <?php endif; ?>
admin/views/ad-parameters-metabox.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php $types = Advanced_Ads::get_instance()->ad_types; ?>
2
+ <h4><?php _e('Ad Parameters', Advanced_Ads::TD); ?></h4>
3
+ <?php
4
+ /**
5
+ * when changing ad type ad parameter content is loaded via ajax
6
+ * @filesource admin/assets/js/admin.js
7
+ * @filesource includes/class-ajax-callbacks.php ::load_ad_parameters_metabox
8
+ * @filesource classes/ad-type-content.php :: renter_parameters()
9
+ */
10
+ ?>
11
+ <div id="advanced-ads-ad-parameters">
12
+ <?php $type = (isset($types[$ad->type])) ? $types[$ad->type] : current($types);
13
+ $type->render_parameters($ad); ?>
14
+ </div>
15
+ <?php do_action('advanced-ads-ad-params-after', $ad, $types);
admin/views/admin.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Represents the view for the administration dashboard.
4
+ *
5
+ * This includes the header, options, and other information that should provide
6
+ * The User Interface to the end user.
7
+ *
8
+ * @package Advanced_Ads_Admin
9
+ * @author Thomas Maier <thomas.maier@webgilde.com>
10
+ * @license GPL-2.0+
11
+ * @link http://webgilde.com
12
+ * @copyright 2013 Thomas Maier, webgilde GmbH
13
+ */
14
+ ?>
15
+
16
+ <div class="wrap">
17
+ <h2 style="color:red;"><?php _e('Work in progress', $this->plugin_slug); ?></h2>
18
+ <p><?php _e('This screen is work in progress. You can use the information if you understand them, but there is nothing to do here yet.', $this->plugin_slug); ?></p>
19
+ <?php screen_icon(); ?>
20
+ <h1><?php echo esc_html(get_admin_page_title()); ?></h1>
21
+
22
+ <h2><?php _e('Ad Condition Overview', $this->plugin_slug); ?></h2>
23
+ <pre><?php print_r($ads_by_conditions); ?></pre>
24
+
25
+ </div>
admin/views/debug.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * the view for the debug page
4
+ */
5
+ ?>
6
+
7
+ <div class="wrap">
8
+ <h2 style="color:red;"><?php _e('Work in progress', $this->plugin_slug); ?></h2>
9
+ <p><?php _e('This screen is work in progress. You can use the information if you understand them, but there is nothing to do here yet.', $this->plugin_slug); ?></p>
10
+ <?php screen_icon(); ?>
11
+ <h1><?php echo esc_html(get_admin_page_title()); ?></h1>
12
+
13
+ <h2><?php _e('Ad Condition Overview', $this->plugin_slug); ?></h2>
14
+ <pre><?php print_r($ads_by_conditions); ?></pre>
15
+
16
+ </div>
admin/views/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php // Silence is golden
admin/views/settings.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * the view for the settings page
4
+ */
5
+ ?>
6
+
7
+ <div class="wrap">
8
+ <?php screen_icon(); ?>
9
+ <h1><?php echo esc_html(get_admin_page_title()); ?></h1>
10
+ <form method="POST" action="options.php">
11
+ <?php
12
+ /**
13
+ * only display setting field if any registered
14
+ * @TODO remove when base plugin has its own settings
15
+ */
16
+ global $wp_settings_fields;
17
+
18
+ if(isset($wp_settings_fields['advanced_ads_page_advanced-ads-settings'])){
19
+ settings_fields($this->plugin_screen_hook_suffix);
20
+ do_settings_sections( $this->plugin_screen_hook_suffix);
21
+
22
+ do_action('advanced-ads-settings-form');
23
+ submit_button();
24
+ } else {
25
+ echo '<p>'.__('No settings available yet', $this->plugin_slug).'</p>';
26
+ }
27
+
28
+ ?>
29
+ </form>
30
+ <hr/>
31
+ <ul>
32
+ <li><a href="/wp-admin/edit.php?post_type=advanced_ads&page=advanced-ads-debug"><?php _e('Debug Page', $this->plugin_slug); ?></a></li>
33
+ <li><a href="http://wordpress.org/plugins/advanced-ads/" title="<?php _e('Advanced Ads on WordPress.org', $this->plugin_slug); ?>"><?php _e('Advanced Ads on wp.org', $this->plugin_slug); ?></a></li>
34
+ <li><a href="http://webgilde.com" title="<?php _e('the company behind Advanced Ads', $this->plugin_slug); ?>"><?php _e('webgilde GmbH', $this->plugin_slug); ?></a></li>
35
+ </ul>
36
+
37
+ </div>
advanced-ads.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Advanced Ads.
4
+ *
5
+ * @package Advanced_Ads_Admin
6
+ * @author Thomas Maier <thomas.maier@webgilde.com>
7
+ * @license GPL-2.0+
8
+ * @link http://webgilde.com
9
+ * @copyright 2013 Thomas Maier, webgilde GmbH
10
+ *
11
+ * @wordpress-plugin
12
+ * Plugin Name: Advanced Ads
13
+ * Plugin URI: http://webgilde.com
14
+ * Description: Manage and optimize your ads in WordPress
15
+ * Version: 1.0.1
16
+ * Author: Thomas Maier
17
+ * Author URI: http://webgilde.com
18
+ * Text Domain: advanced-ads
19
+ * License: GPL-2.0+
20
+ * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
21
+ * Domain Path: /languages
22
+ */
23
+
24
+ // If this file is called directly, abort.
25
+ if ( ! defined( 'WPINC' ) ) {
26
+ die;
27
+ }
28
+
29
+ // only load if not already existing (maybe within another plugin I created)
30
+ if(!class_exists('Advanced_Ads')) {
31
+
32
+ // load basic path to the plugin
33
+ DEFINE('ADVADS_BASE_PATH', plugin_dir_path(__FILE__));
34
+ // general and global slug, e.g. to store options in WP
35
+ DEFINE('ADVADS_SLUG', 'advancedads');
36
+
37
+ /*----------------------------------------------------------------------------*
38
+ * Autoloading Objects
39
+ *----------------------------------------------------------------------------*/
40
+ require_once( plugin_dir_path( __FILE__ ) . 'includes/autoloader.php' );
41
+ spl_autoload_register(array('Advads_Autoloader', 'load'));
42
+
43
+ /*----------------------------------------------------------------------------*
44
+ * Public-Facing Functionality
45
+ *----------------------------------------------------------------------------*/
46
+
47
+ require_once( plugin_dir_path( __FILE__ ) . 'public/class-advanced-ads.php' );
48
+
49
+ /*
50
+ * Register hooks that are fired when the plugin is activated or deactivated.
51
+ * When the plugin is deleted, the uninstall.php file is loaded.
52
+ *
53
+ */
54
+ register_activation_hook( __FILE__, array( 'Advanced_Ads', 'activate' ) );
55
+ register_deactivation_hook( __FILE__, array( 'Advanced_Ads', 'deactivate' ) );
56
+
57
+ add_action( 'plugins_loaded', array( 'Advanced_Ads', 'get_instance' ) );
58
+
59
+ /*----------------------------------------------------------------------------*
60
+ * Dashboard and Administrative Functionality
61
+ *----------------------------------------------------------------------------*/
62
+
63
+ if( defined('DOING_AJAX') ) {
64
+ require_once( plugin_dir_path( __FILE__ ) . 'includes/class_ajax_callbacks.php' );
65
+ }
66
+ // load ad conditions array
67
+ require_once( plugin_dir_path( __FILE__ ) . 'includes/array_ad_conditions.php' );
68
+
69
+ if ( is_admin() && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) ) {
70
+
71
+ require_once( plugin_dir_path( __FILE__ ) . 'admin/class-advanced-ads-admin.php' );
72
+ add_action( 'plugins_loaded', array( 'Advanced_Ads_Admin', 'get_instance' ) );
73
+
74
+ }
75
+
76
+ // load public functions
77
+ require_once( plugin_dir_path( __FILE__ ) . 'public/functions.php' );
78
+
79
+ }
assets/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php // Silence is golden
assets/screenshot-1.png ADDED
Binary file
assets/screenshot-2.png ADDED
Binary file
classes/ad.php ADDED
@@ -0,0 +1,560 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Advanced Ads.
5
+ *
6
+ * @package Advads_Ad
7
+ * @author Thomas Maier <thomas.maier@webgilde.com>
8
+ * @license GPL-2.0+
9
+ * @link http://webgilde.com
10
+ * @copyright 2013 Thomas Maier, webgilde GmbH
11
+ */
12
+
13
+ /**
14
+ * an ad object
15
+ *
16
+ * @package Advads_Ad
17
+ * @author Thomas Maier <thomas.maier@webgilde.com>
18
+ */
19
+ class Advads_Ad {
20
+
21
+ /**
22
+ * id of the post type for this ad
23
+ */
24
+ protected $id = 0;
25
+
26
+ /**
27
+ * true, if this is an Advanced Ads Ad post type
28
+ */
29
+ protected $is_ad = false;
30
+
31
+ /**
32
+ * ad type
33
+ */
34
+ public $type = 'content';
35
+
36
+ /**
37
+ * object of current ad type
38
+ */
39
+ protected $type_obj;
40
+
41
+ /**
42
+ * content of the ad
43
+ *
44
+ * only needed for ad types using the post content field
45
+ */
46
+ public $content = '';
47
+
48
+ /**
49
+ * conditions of the ad display
50
+ */
51
+ public $conditions = array();
52
+
53
+ /**
54
+ * status of the ad (e.g. publish, pending)
55
+ */
56
+ public $status = array();
57
+
58
+ /**
59
+ * array with meta field options aka parameters
60
+ */
61
+ protected $options = array();
62
+
63
+ /**
64
+ * name of the meta field to save options to
65
+ */
66
+ static $options_meta_field = 'advanced_ads_ad_options';
67
+
68
+ /**
69
+ * init ad object
70
+ *
71
+ * @param int $id id of the ad (= post id)
72
+ */
73
+ public function __construct($id) {
74
+ global $advanced_ads_ad_conditions;
75
+ $id = absint($id);
76
+ $this->id = $id;
77
+
78
+ if(!empty($id)) $this->load($id);
79
+
80
+ // dynamically add sanitize filters for condition types
81
+ foreach($advanced_ads_ad_conditions as $_condition) {
82
+ $_types[] = $_condition['type'];
83
+ }
84
+ $_types = array_unique($_types);
85
+ foreach($_types as $_type) {
86
+ $method_name = 'sanitize_condition_'. $_type;
87
+ if(method_exists($this, $method_name)) {
88
+ add_filter('advanced-ads-sanitize-condition-' . $_type, array($this, $method_name), 10, 1);
89
+ } elseif(function_exists('advads_sanitize_condition_' . $_type)) {
90
+ // check for public function to sanitize this
91
+ add_filter('advanced-ads-sanitize-condition-' . $_type, 'advads_sanitize_condition_' . $_type, 10, 1);
92
+
93
+ }
94
+ }
95
+ }
96
+
97
+ /**
98
+ * load an ad object by id based on its ad type
99
+ *
100
+ * @since 1.0.0
101
+ */
102
+ private function load($id = 0){
103
+
104
+ $_data = get_post($id);
105
+ if($_data == null) return false;
106
+
107
+ // return, if not an ad
108
+ if($_data->post_type != Advanced_Ads::POST_TYPE_SLUG) {
109
+ return false;
110
+ } else {
111
+ $this->is_ad = true;
112
+ }
113
+
114
+ $this->type = $this->options('type');
115
+ /* load ad type object */
116
+ $types = Advanced_Ads::get_instance()->ad_types;
117
+ if(isset($types[$this->type])){
118
+ $this->type_obj = $types[$this->type];
119
+ } else {
120
+ $this->type_obj = new Advads_Ad_Type_Abstract;
121
+ }
122
+
123
+ $this->conditions = $this->options('conditions');
124
+ $this->status = $_data->post_status;
125
+
126
+ // load content based on ad type
127
+ $this->content = $this->type_obj->load_content($_data);
128
+ }
129
+
130
+ /**
131
+ * get options from meta field and return specific field
132
+ *
133
+ * @param string $field post meta key to be returned
134
+ * @return mixed meta field content
135
+ * @since 1.0.0
136
+ * @todo check against default values
137
+ */
138
+ public function options($field = ''){
139
+ // retrieve options, if not given yet
140
+ if($this->options == array()) {
141
+ $this->options = get_post_meta($this->id, self::$options_meta_field, true);
142
+ }
143
+
144
+ // return specific option
145
+ if($field != '') {
146
+ if(!empty($this->options[$field]))
147
+ return $this->options[$field];
148
+ } else { // return all options
149
+ if(!empty($this->options))
150
+ return $this->options;
151
+ }
152
+ }
153
+
154
+ /**
155
+ * return ad content for frontend output
156
+ */
157
+ public function output(){
158
+ if(!$this->is_ad) return '';
159
+
160
+ $output = $this->prepare_frontend_output();
161
+ return $output;
162
+ }
163
+
164
+ /**
165
+ * check if the ad can be displayed in frontend due to its conditions
166
+ *
167
+ * @return bool $can_display true if can be displayed in frontend
168
+ */
169
+ public function can_display(){
170
+ global $post;
171
+
172
+ if(empty($this->options['conditions']) ||
173
+ !is_array($this->options['conditions'])) return true;
174
+
175
+ $conditions = $this->options['conditions'];
176
+ foreach($conditions as $_cond_key => $_cond_value) {
177
+ switch($_cond_key){
178
+ // check for post ids
179
+ case 'postids' :
180
+ // included posts
181
+ if(!empty($_cond_value['include'])){
182
+ $post_ids = explode(',', $_cond_value['include']);
183
+ if(is_array($post_ids)
184
+ && isset($post->ID)
185
+ && !in_array($post->ID, $post_ids))
186
+ return false;
187
+ }
188
+ // excluded posts
189
+ if(!empty($_cond_value['exclude'])){
190
+ $post_ids = explode(',', $_cond_value['exclude']);
191
+ if(is_array($post_ids)
192
+ && isset($post->ID)
193
+ && in_array($post->ID, $post_ids))
194
+ return false;
195
+ }
196
+ break;
197
+ // check for category ids
198
+ case 'categoryids' :
199
+ // included
200
+ if(!empty($_cond_value['include'])){
201
+ $category_ids = explode(',', $_cond_value['include']);
202
+ // check if currently in a post (not post page, but also posts in loops)
203
+ if(is_array($category_ids) && isset($post->ID)
204
+ && !in_category($category_ids, $post)) {
205
+ return false;
206
+ }
207
+ }
208
+ // check for excluded category ids
209
+ if(!empty($_cond_value['exclude'])){
210
+ $category_ids = explode(',', $_cond_value['exclude']);
211
+ // check if currently in a post (not post page, but also posts in loops)
212
+ if(is_array($category_ids) && isset($post->ID)
213
+ && in_category($category_ids, $post) ) {
214
+ // being only in one excluded category is enough to not display the ad
215
+ return false;
216
+ }
217
+ }
218
+ break;
219
+ // check for included category archive ids
220
+ // @link http://codex.wordpress.org/Conditional_Tags#A_Category_Page
221
+ case 'categoryarchiveids' :
222
+ if(!empty($_cond_value['include'])){
223
+ $category_ids = explode(',', $_cond_value['include']);
224
+ if(is_array($category_ids) && !is_category($category_ids))
225
+ return false;
226
+ }
227
+ // check for excluded category archive ids
228
+ if(!empty($_cond_value['exclude'])){
229
+ $category_ids = explode(',', $_cond_value['exclude']);
230
+ if(is_array($category_ids) && is_category($category_ids))
231
+ return false;
232
+ }
233
+ break;
234
+ // check for included post types
235
+ case 'posttypes' :
236
+ if(!empty($_cond_value['include'])){
237
+ $post_types = explode(',', $_cond_value['include']);
238
+ // check if currently in a post (not post page, but also posts in loops)
239
+ if(is_array($post_types) && !in_array(get_post_type(), $post_types)) {
240
+ return false;
241
+ }
242
+ }
243
+ // check for excluded post types
244
+ if(!empty($_cond_value['include'])){
245
+ $post_types = explode(',', $_cond_value['exclude']);
246
+ // check if currently in a post (not post page, but also posts in loops)
247
+ if(is_array($post_types) && in_array(get_post_type(), $post_types)) {
248
+ return false;
249
+ }
250
+ }
251
+ break;
252
+ // check is_front_page
253
+ // @link https://codex.wordpress.org/Conditional_Tags#The_Front_Page
254
+ case 'is_front_page' :
255
+ if(($_cond_value == 1 && !is_front_page())
256
+ || ($_cond_value == 0 && is_front_page()))
257
+ return false;
258
+ break;
259
+ // check is_singular
260
+ // @link https://codex.wordpress.org/Conditional_Tags#A_Post_Type
261
+ case 'is_singular' :
262
+ if(($_cond_value == 1 && !is_singular())
263
+ || ($_cond_value == 0 && is_singular()))
264
+ return false;
265
+ break;
266
+ // check is_archive
267
+ // @link https://codex.wordpress.org/Conditional_Tags#Any_Archive_Page
268
+ case 'is_archive' :
269
+ if(($_cond_value == 1 && !is_archive())
270
+ || ($_cond_value == 0 && is_archive()))
271
+ return false;
272
+ break;
273
+ // check is_search
274
+ // @link https://codex.wordpress.org/Conditional_Tags#A_Search_Result_Page
275
+ case 'is_search' :
276
+ if(($_cond_value == 1 && !is_search())
277
+ || ($_cond_value == 0 && is_search()))
278
+ return false;
279
+ break;
280
+ // check is_404
281
+ // @link https://codex.wordpress.org/Conditional_Tags#A_404_Not_Found_Page
282
+ case 'is_404' :
283
+ if(($_cond_value == 1 && !is_404())
284
+ || ($_cond_value == 0 && is_404()))
285
+ return false;
286
+ break;
287
+ // check is_attachment
288
+ // @link https://codex.wordpress.org/Conditional_Tags#An_Attachment
289
+ case 'is_attachment' :
290
+ if(($_cond_value == 1 && !is_attachment())
291
+ || ($_cond_value == 0 && is_attachment()))
292
+ return false;
293
+ break;
294
+ }
295
+ }
296
+
297
+ return true;
298
+ }
299
+
300
+ /**
301
+ * save an ad to the database
302
+ * takes values from the current state
303
+ */
304
+ public function save(){
305
+ global $wpdb;
306
+
307
+ // remove slashes from content
308
+ $content = $this->prepare_content_to_save();
309
+
310
+ $where = array('ID' => $this->id);
311
+ $wpdb->update( $wpdb->posts, array( 'post_content' => $content ), $where );
312
+
313
+ // sanitize conditions
314
+ // see sanitize_conditions function for example on using this filter
315
+ $conditions = self::sanitize_conditions_on_save($this->conditions);
316
+
317
+ // save other options to post meta field
318
+ $options = array(
319
+ 'type' => $this->type,
320
+ 'conditions' => $conditions,
321
+ );
322
+
323
+ // filter to manipulate options or add more to be saved
324
+ $options = apply_filters('advanced-ads-save-options', $options, $this);
325
+
326
+ $this->update_general_ad_conditions($conditions);
327
+
328
+ update_post_meta($this->id, self::$options_meta_field, $options);
329
+
330
+ }
331
+
332
+ /**
333
+ * native filter for content field before being saved
334
+ *
335
+ * @return string $content ad content
336
+ * @since 1.0.0
337
+ */
338
+ public function prepare_content_to_save() {
339
+
340
+ $content = $this->content;
341
+
342
+ // load ad type specific parameter filter
343
+ $content = $this->type_obj->sanitize_content($content);
344
+ // apply a custom filter by ad type
345
+ $content = apply_filters('advanced-ads-pre-ad-save-' . $this->type, $content);
346
+
347
+ return $content;
348
+ }
349
+
350
+ /**
351
+ * native filter for ad parameters before being saved
352
+ *
353
+ * @return arr $parameters sanitized parameters
354
+ */
355
+ public function prepare_parameters_to_save() {
356
+
357
+ $parameters = $this->parameters;
358
+ // load ad type specific parameter filter
359
+ $parameters = $this->type_obj->sanitize_parameters($parameters);
360
+
361
+ // apply native WP filter for content fields
362
+ return $parameters;
363
+ }
364
+
365
+ /**
366
+ * prepare ads output
367
+ *
368
+ * @param string $content ad content
369
+ * @param obj $ad ad object
370
+ */
371
+ public function prepare_frontend_output(){
372
+
373
+ // load ad type specific content filter
374
+ $output = $this->type_obj->prepare_output($this);
375
+
376
+ // apply a custom filter by ad type
377
+ $output = apply_filters('advanced-ads-ad-output', $output, $this);
378
+
379
+ return $output;
380
+ }
381
+
382
+ /**
383
+ * sanitize ad display conditions when saving the ad
384
+ *
385
+ * @param array $conditions conditions array send via the dashboard form for an ad
386
+ * @return array with sanitized conditions
387
+ * @since 1.0.0
388
+ */
389
+ public function sanitize_conditions_on_save($conditions = array()){
390
+
391
+ global $advanced_ads_ad_conditions;
392
+
393
+ if(!is_array($conditions) || $conditions == array()) return array();
394
+
395
+ foreach($conditions as $_key => $_condition){
396
+ if(!is_array($_condition))
397
+ $_condition = trim($_condition);
398
+ if($_condition == '') {
399
+ $conditions[$_key] = $_condition;
400
+ continue;
401
+ }
402
+ $type = $advanced_ads_ad_conditions[$_key]['type'];
403
+ if(empty($type)) continue;
404
+
405
+ // dynamically apply filters for each condition used
406
+ $conditions[$_key] = apply_filters('advanced-ads-sanitize-condition-' . $type, $_condition);
407
+ }
408
+
409
+ return $conditions;
410
+ }
411
+
412
+ /**
413
+ * sanitize id input field(s) for pattern /1,2,3,4/
414
+ *
415
+ * @pararm array/string $cond input string/array
416
+ * @return array/string $cond sanitized string/array
417
+ */
418
+ public static function sanitize_condition_idfield($cond = ''){
419
+ // strip anything that is not comma or number
420
+ if(is_array($cond)){
421
+ foreach($cond as $_key => $_cond){
422
+ $cond[$_key] = preg_replace('#[^0-9,]#', '', $_cond);
423
+ }
424
+ } else {
425
+ $cond = preg_replace('#[^0-9,]#', '', $cond);
426
+ }
427
+ return $cond;
428
+ }
429
+
430
+ /**
431
+ * sanitize radio input field
432
+ *
433
+ * @pararm string $string input string
434
+ * @return string $string sanitized string
435
+ */
436
+ public static function sanitize_condition_radio($string = ''){
437
+ // only allow 0, 1 and empty
438
+ return $string = preg_replace('#[^01]#', '', $string);
439
+ }
440
+
441
+ /**
442
+ * sanitize comma seperated text input field
443
+ *
444
+ * @pararm array/string $cond input string/array
445
+ * @return array/string $cond sanitized string/array
446
+ */
447
+ public static function sanitize_condition_textvalues($cond = ''){
448
+ // strip anything that is not comma, alphanumeric, minus and underscore
449
+ if(is_array($cond)){
450
+ foreach($cond as $_key => $_cond){
451
+ $cond[$_key] = preg_replace('#[^0-9,A-Za-z-_]#', '', $_cond);
452
+ }
453
+ } else {
454
+ $cond = preg_replace('#[^0-9,A-Za-z-_]#', '', $cond);
455
+ }
456
+ return $cond;
457
+ }
458
+
459
+ /**
460
+ * update general ad conditions with conditions for the current ad
461
+ *
462
+ * @param array $conditions ad display conditions from ad form
463
+ * @since 1.0.0
464
+ * @todo make those condition checks extendible
465
+ */
466
+ public function update_general_ad_conditions($conditions){
467
+ global $advanced_ads_ad_conditions;
468
+
469
+ $plugin = Advanced_Ads::get_instance();
470
+ $ads_by_conditions = $plugin->get_ads_by_conditions_array();
471
+ $plugin_slug = $plugin->get_plugin_slug();
472
+
473
+ // remove current ad from general ad condition array
474
+ $ads_by_conditions = $this->remove_ad_from_general_ad_conditions($this->id, $ads_by_conditions);
475
+
476
+ // only run conditions if ad is publically visible
477
+ if($this->status == 'publish')
478
+ // iterate through the ads display condition
479
+ foreach($conditions as $_condition_key => $_condition){
480
+ if(!isset($advanced_ads_ad_conditions[$_condition_key]['type'])) {
481
+ $plugin->log(sprintf(__('A "%s" display condition does not exist', $plugin_slug), $_condition_key));
482
+ return;
483
+ }
484
+ // add conditions based on type
485
+ switch($advanced_ads_ad_conditions[$_condition_key]['type']){
486
+ case 'idfield' :
487
+ if(isset($_condition['include']) && $_condition['include'] != ''){
488
+ $_ids = explode(',', $_condition['include']);
489
+ if(is_array($_ids)) foreach($_ids as $_id){
490
+ $ads_by_conditions[$_condition_key][$_id]['include'][] = $this->id;
491
+ }
492
+ }
493
+ if(isset($_condition['exclude']) && $_condition['exclude'] != ''){
494
+ $_ids = explode(',', $_condition['exclude']);
495
+ if(is_array($_ids)) foreach($_ids as $_id){
496
+ $ads_by_conditions[$_condition_key][$_id]['exclude'][] = $this->id;
497
+ }
498
+ }
499
+ break;
500
+ case 'textvalues' :
501
+ if(isset($_condition['include']) && $_condition['include'] != ''){
502
+ $_ids = explode(',', $_condition['include']);
503
+ if(is_array($_ids)) foreach($_ids as $_id){
504
+ $ads_by_conditions[$_condition_key][$_id]['include'][] = $this->id;
505
+ }
506
+ }
507
+ if(isset($_condition['exclude']) && $_condition['exclude'] != ''){
508
+ $_ids = explode(',', $_condition['exclude']);
509
+ if(is_array($_ids)) foreach($_ids as $_id){
510
+ $ads_by_conditions[$_condition_key][$_id]['exclude'][] = $this->id;
511
+ }
512
+ }
513
+ break;
514
+ case 'radio' :
515
+ if($_condition == 1)
516
+ $ads_by_conditions[$_condition_key]['include'][] = $this->id;
517
+ elseif($_condition == 0)
518
+ $ads_by_conditions[$_condition_key]['exclude'][] = $this->id;
519
+ break;
520
+ } // switch
521
+ } // forearch
522
+
523
+ update_option('advads-ads-by-conditions', $ads_by_conditions);
524
+ }
525
+
526
+ /**
527
+ * remove ad id from ad conditions array
528
+ *
529
+ * @param int $ad_id id of the ad (=post id)
530
+ * @param arr $conditions array with the general, global ad conditions
531
+ * @since 1.0.0
532
+ */
533
+ static function remove_ad_from_general_ad_conditions($ad_id = 0, $conditions = array()){
534
+ $ad_id = absint($ad_id);
535
+ if(empty($ad_id) || !is_array($conditions) || $conditions == array()) return;
536
+
537
+ foreach($conditions as $_key => $_cond){
538
+ // remove single elements
539
+ if(!is_array($_cond) && $_cond == $ad_id){
540
+ unset($conditions[$_key]);
541
+ } elseif(empty($_cond)){
542
+ unset($conditions[$_key]);
543
+ }
544
+ // check recursively
545
+ elseif(is_array($_cond)){
546
+ $new_cond = self::remove_ad_from_general_ad_conditions($ad_id, $_cond);
547
+
548
+ if($new_cond == array() || $new_cond == ''){
549
+ // remove empty arrays
550
+ unset($conditions[$_key]);
551
+ } else {
552
+ $conditions[$_key] = $new_cond;
553
+ }
554
+ }
555
+ }
556
+
557
+ return $conditions;
558
+ }
559
+
560
+ }
classes/ad_group.php ADDED
@@ -0,0 +1,345 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Advanced Ads
5
+ *
6
+ * @package Advads_Ad_Group
7
+ * @author Thomas Maier <thomas.maier@webgilde.com>
8
+ * @license GPL-2.0+
9
+ * @link http://webgilde.com
10
+ * @copyright 2014 Thomas Maier, webgilde GmbH
11
+ */
12
+
13
+ /**
14
+ * an ad group object
15
+ *
16
+ * @package Advads_Ad_Group
17
+ * @author Thomas Maier <thomas.maier@webgilde.com>
18
+ */
19
+ class Advads_Ad_Group {
20
+
21
+ /**
22
+ * default ad group weight
23
+ */
24
+ const MAX_AD_GROUP_WEIGHT = 10;
25
+
26
+ /**
27
+ * id of the taxonomy of this ad group
28
+ */
29
+ protected $id = 0;
30
+
31
+ /**
32
+ * name of the taxonomy
33
+ */
34
+ protected $taxonomy = '';
35
+
36
+ /**
37
+ * post type of the ads
38
+ */
39
+ protected $post_type = '';
40
+
41
+ /**
42
+ * the current loaded ad
43
+ */
44
+ protected $current_ad = '';
45
+
46
+ /**
47
+ * the name of the term
48
+ */
49
+ public $name = '';
50
+
51
+ /**
52
+ * the slug of the term
53
+ */
54
+ public $slug = '';
55
+
56
+ /**
57
+ * the description of the term
58
+ */
59
+ public $description = '';
60
+
61
+ /**
62
+ * containing ad weights
63
+ */
64
+ private $ad_weights = 0;
65
+
66
+ /**
67
+ * array with post type objects (ads)
68
+ */
69
+ private $ads = array();
70
+
71
+ /**
72
+ * init ad group object
73
+ *
74
+ * @since 1.0.0
75
+ * @param int $id id of the ad group (= taxonomy id)
76
+ */
77
+ public function __construct($id) {
78
+ $id = absint($id);
79
+
80
+ if (empty($id))
81
+ return;
82
+
83
+ $this->id = $id;
84
+ $this->taxonomy = Advanced_Ads::AD_GROUP_TAXONOMY;
85
+ $this->post_type = Advanced_Ads::POST_TYPE_SLUG;
86
+
87
+ $this->load($id);
88
+ }
89
+
90
+ /**
91
+ * load an ad group object by id
92
+ *
93
+ * @since 1.0.0
94
+ */
95
+ private function load($id = 0) {
96
+ $_group = get_term($id, $this->taxonomy);
97
+ if ($_group == null)
98
+ return;
99
+
100
+ $this->name = $_group->name;
101
+ $this->slug = $_group->slug;
102
+ $this->description = $_group->description;
103
+ }
104
+
105
+ /**
106
+ * return random ad content for frontend output
107
+ *
108
+ * @since 1.0.0
109
+ * @return string ad content
110
+ */
111
+ public function output_random_ad() {
112
+ // see prepare_frontend_output for example for this filter
113
+ $ad = $this->get_random_ad();
114
+
115
+ if (!is_object($ad))
116
+ return '';
117
+
118
+ // makes sure the ad filters can also run here
119
+ $adcontent = $ad->output();
120
+
121
+ // filter again, in case a developer wants to filter group output individually
122
+ $output = apply_filters('advanced-ads-group-output', $adcontent, $this);
123
+
124
+ return $output;
125
+ }
126
+
127
+ /**
128
+ * get a random ad from this group
129
+ *
130
+ * @since 1.0.0
131
+ * @return
132
+ */
133
+ private function get_random_ad() {
134
+
135
+ // load all ads
136
+ $ads = $this->load_all_ads();
137
+
138
+ // return, if no ads given
139
+ if ($ads === array())
140
+ return;
141
+
142
+ // shuffle ads based on ad weight
143
+ $ads = $this->shuffle_ads($ads);
144
+
145
+ // check ads one by one for being able to be displayed on this spot
146
+ foreach ($ads as $_ad) {
147
+ // load the ad object
148
+ $ad = new Advads_Ad($_ad->ID);
149
+ if ($ad->can_display()) {
150
+ return $ad;
151
+ }
152
+ }
153
+
154
+ return '';
155
+ }
156
+
157
+ /**
158
+ * return all ads from this group
159
+ *
160
+ * @since 1.0.0
161
+ */
162
+ public function get_all_ads() {
163
+ if(count($this->ads) == 0)
164
+ return $this->ads;
165
+ else
166
+ return $this->load_all_ads();
167
+ }
168
+
169
+ /**
170
+ * load all ads for this group
171
+ *
172
+ * @since 1.0.0
173
+ * @return arr $ads array with ad (post) objects
174
+ */
175
+ private function load_all_ads() {
176
+
177
+ $args = array(
178
+ 'post_type' => $this->post_type,
179
+ $this->taxonomy => $this->slug,
180
+ 'orderby' => 'id'
181
+ );
182
+ $ads = new WP_Query($args);
183
+ // not sure if reset of postdata is needed here
184
+ wp_reset_postdata();
185
+
186
+ if ($ads->have_posts()) {
187
+ return $this->ads = $this->add_post_ids($ads->posts);
188
+ } else {
189
+ return $this->ads = array();
190
+ }
191
+ }
192
+
193
+ /**
194
+ * use post ids as keys for ad array
195
+ *
196
+ * @since 1.0.0
197
+ * @param arr $ads array with post objects
198
+ * @return arr $ads array with post objects with post id as their key
199
+ * @todo check, if there isn’t a WP function for this already
200
+ */
201
+ private function add_post_ids(array $ads){
202
+
203
+ $ads_with_id = array();
204
+ foreach($ads as $_ad){
205
+ $ads_with_id[$_ad->ID] = $_ad;
206
+ }
207
+
208
+ return $ads_with_id;
209
+ }
210
+
211
+ /**
212
+ * shuffle ads based on ad weight
213
+ *
214
+ * @since 1.0.0
215
+ * @param arr $ads array with ad objects
216
+ * @return arr $shuffled_ads shuffled array with ad objects
217
+ */
218
+ private function shuffle_ads($ads = array()) {
219
+
220
+ // get saved ad weights
221
+ $weights = $this->get_ad_weights();
222
+
223
+ // if ads and weights don’t have the same keys, update weights array
224
+ if(count($weights) != count($ads) || array_diff_key($weights, $ads) != array()
225
+ || array_diff_key($ads, $weights) != array()) {
226
+ $this->update_ad_weights();
227
+ }
228
+
229
+ // get a random ad for every ad there is
230
+ $shuffled_ads = array();
231
+ $ad_count = count($ads);
232
+ for($i = 1; $i <= $ad_count; $i++){
233
+ $random_ad_id = $this->get_random_ad_by_weight($weights);
234
+ // remove chosen ad from weights array
235
+ unset($weights[$random_ad_id]);
236
+ // put random ad into shuffled array
237
+ if(isset($ads[$random_ad_id])) { $shuffled_ads[] = $ads[$random_ad_id]; }
238
+ }
239
+
240
+ return $shuffled_ads;
241
+ }
242
+
243
+ /**
244
+ * get random ad by ad weight
245
+ *
246
+ * @since 1.0.0
247
+ * @param array $ad_weights e.g. array(A => 2, B => 3, C => 5)
248
+ * @source applied with fix for order http://stackoverflow.com/a/11872928/904614
249
+ */
250
+ private function get_random_ad_by_weight(array $ad_weights) {
251
+
252
+ // order array by ad weight; lowest first
253
+ asort($ad_weights);
254
+
255
+ // use maximum ad weight for ads without this
256
+ $max = (int) array_sum($ad_weights);
257
+ $rand = mt_rand(1, $max);
258
+
259
+ foreach ($ad_weights as $key => $value) {
260
+ $rand -= $value;
261
+ if ($rand <= 0) {
262
+ return $key;
263
+ }
264
+ }
265
+ }
266
+
267
+ /**
268
+ * get weights of ads in this group
269
+ *
270
+ * @since 1.0.0
271
+ */
272
+ public function get_ad_weights() {
273
+ if ($this->ad_weights == 0) {
274
+ $weights = get_option('advads-ad-weights', array());
275
+ } else {
276
+ return $this->ad_weights;
277
+ }
278
+ if (isset($weights[$this->id])) {
279
+ return $this->ad_weights = $weights[$this->id];
280
+ }
281
+ }
282
+
283
+ /**
284
+ * save ad group weight (into global ad weight array)
285
+ *
286
+ * @since 1.0.0
287
+ * @param arr|str $weights array with ad weights (key: ad id; value: weight)
288
+ */
289
+ public function save_ad_weights($weights = '') {
290
+
291
+ // allow only arrays and empty string
292
+ if (!is_array($weights) && $weights = '')
293
+ return;
294
+
295
+ $global_weights = get_option('advads-ad-weights', array());
296
+
297
+ $global_weights[$this->id] = $this->sanitize_ad_weights($weights);
298
+
299
+ update_option('advads-ad-weights', $global_weights);
300
+ }
301
+ /**
302
+ * update ad weight based on current ads for the group and ad weight
303
+ *
304
+ * @since 1.0.0
305
+ */
306
+ private function update_ad_weights(){
307
+ $ads = $this->get_all_ads();
308
+ $weights = $this->get_ad_weights();
309
+
310
+ $new_weights = array();
311
+ // use only ads assigned to the group
312
+ foreach($ads as $_ad){
313
+ if(isset($weights[$_ad->ID])){
314
+ $new_weights[$_ad->ID] = $weights[$_ad->ID];
315
+ } else {
316
+ // if no weight is given, use maximum default value
317
+ $new_weights[$_ad->ID] = self::MAX_AD_GROUP_WEIGHT;
318
+ }
319
+ }
320
+
321
+ $this->save_ad_weights($new_weights);
322
+ }
323
+
324
+ /**
325
+ * sanitize ad weights
326
+ *
327
+ * @since 1.0.0
328
+ * @param arr $weights ad weights array with (key: ad id; value: weight)
329
+ */
330
+ private function sanitize_ad_weights($weights = array()) {
331
+
332
+ if (!is_array($weights))
333
+ return '';
334
+
335
+ $sanitized_weights = array();
336
+ foreach ($weights as $_ad_id => $_weight) {
337
+ $_ad_id = absint($_ad_id);
338
+ $_weight = absint($_weight);
339
+ $sanitized_weights[$_ad_id] = $_weight;
340
+ }
341
+
342
+ return $sanitized_weights;
343
+ }
344
+
345
+ }
classes/ad_type_abstract.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Advanced Ads Abstract Ad Type
4
+ *
5
+ * @package Advanced_Ads
6
+ * @author Thomas Maier <thomas.maier@webgilde.com>
7
+ * @license GPL-2.0+
8
+ * @link http://webgilde.com
9
+ * @copyright 2014 Thomas Maier, webgilde GmbH
10
+ *
11
+ * Class containing information that are defaults for all the other ad types
12
+ *
13
+ * see ad_type_content.php for an example on ad type
14
+ *
15
+ */
16
+ class Advads_Ad_Type_Abstract {
17
+
18
+ /**
19
+ * ID - internal type of the ad type
20
+ *
21
+ * must be static so set your own ad type ID here
22
+ * use slug like format, only lower case, underscores and hyphens
23
+ *
24
+ * @since 1.0.0
25
+ */
26
+ public $ID = '';
27
+
28
+ /**
29
+ * public title
30
+ *
31
+ * will be set within __construct so one can localize it
32
+ *
33
+ * @since 1.0.0
34
+ */
35
+ public $title = '';
36
+
37
+ /**
38
+ * description of the ad type
39
+ *
40
+ * will be set within __construct so one can localize it
41
+ *
42
+ * @since 1.0.0
43
+ */
44
+ public $description = '';
45
+
46
+ /**
47
+ * parameters of the ad
48
+ *
49
+ * defaults are set in construct
50
+ */
51
+ public $parameters = array();
52
+
53
+ /**
54
+ * set basic attributes
55
+ *
56
+ * @since 1.0.0
57
+ */
58
+ public function __construct() {
59
+ // initiall
60
+ }
61
+
62
+ /**
63
+ * output for the ad parameters metabox
64
+ *
65
+ * @param obj $ad ad object
66
+ * @since 1.0.0
67
+ */
68
+ public function render_parameters($ad){
69
+ /**
70
+ * this will be loaded by default or using ajax when changing the ad type radio buttons
71
+ * echo the output right away here
72
+ * name parameters must be in the "advanced_ads" array
73
+ */
74
+ }
75
+
76
+ /**
77
+ * sanitize ad parameters on save
78
+ *
79
+ * @param arr $parameters array with ad parameters
80
+ * @return arr $parameters sanitized ad parameters
81
+ * @since 1.0.0
82
+ */
83
+ public function sanitize_parameters($parameters = array()){
84
+ // no specific filter for content ad parameters, because there are no
85
+ return $parameters;
86
+ }
87
+
88
+ /**
89
+ * sanitize content field on save
90
+ *
91
+ * @param str $content ad content
92
+ * @return str $content sanitized ad content
93
+ * @since 1.0.0
94
+ */
95
+ public function sanitize_content($content = ''){
96
+
97
+ // remove slashes from content
98
+ return $content = wp_unslash($content);
99
+ }
100
+
101
+ /**
102
+ * load content field for the ad
103
+ *
104
+ * @param obj $post WP post object
105
+ * @return str $content ad content
106
+ * @since 1.0.0
107
+ */
108
+ public function load_content($post){
109
+
110
+ return $post->post_content;
111
+ }
112
+
113
+ /**
114
+ * prepare the ads frontend output
115
+ *
116
+ * @param obj $ad ad object
117
+ * @return str $content ad content prepared for frontend output
118
+ * @since 1.0.0
119
+ */
120
+ public function prepare_output($ad){
121
+ return $ad->content;
122
+ }
123
+
124
+ }
classes/ad_type_content.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Advanced Ads Content Ad Type
4
+ *
5
+ * @package Advanced_Ads
6
+ * @author Thomas Maier <thomas.maier@webgilde.com>
7
+ * @license GPL-2.0+
8
+ * @link http://webgilde.com
9
+ * @copyright 2014 Thomas Maier, webgilde GmbH
10
+ *
11
+ * Class containing information about the content ad type
12
+ * this should also work as an example for other ad types
13
+ *
14
+ * see also includes/ad-type-abstract.php for basic object
15
+ *
16
+ */
17
+ class Advads_Ad_Type_Content extends Advads_Ad_Type_Abstract{
18
+
19
+ /**
20
+ * ID - internal type of the ad type
21
+ *
22
+ * must be static so set your own ad type ID here
23
+ * use slug like format, only lower case, underscores and hyphens
24
+ *
25
+ * @since 1.0.0
26
+ */
27
+ public $ID = 'content';
28
+
29
+ /**
30
+ * set basic attributes
31
+ *
32
+ * @since 1.0.0
33
+ */
34
+ public function __construct() {
35
+ $this->title = __('Rich Content', Advanced_Ads::TD);
36
+ $this->description = __('The full content editor from WordPress with all features like image upload or styling, but also simple text/html mode for scripts and code.', Advanced_Ads::TD);
37
+ $this->parameters = array(
38
+ 'content' => ''
39
+ );
40
+ }
41
+
42
+ /**
43
+ * output for the ad parameters metabox
44
+ *
45
+ * this will be loaded using ajax when changing the ad type radio buttons
46
+ * echo the output right away here
47
+ * name parameters must be in the "advanced_ads" array
48
+ *
49
+ * @param obj $ad ad object
50
+ * @since 1.0.0
51
+ */
52
+ public function render_parameters($ad){
53
+ // load tinymc content exitor
54
+ $content = (isset($ad->content)) ? $ad->content : '';
55
+ /**
56
+ * build the tinymc editor
57
+ * @link http://codex.wordpress.org/Function_Reference/wp_editor
58
+ */
59
+ $args = array(
60
+ 'textarea_name' => 'advanced_ad[content]',
61
+ 'textarea_rows' => 10,
62
+ 'drag_drop_upload' => true
63
+ );
64
+ wp_editor($content, 'advanced-ad-parameters-content', $args);
65
+ }
66
+
67
+ /**
68
+ * sanitize content field on save
69
+ *
70
+ * @param str $content ad content
71
+ * @return str $content sanitized ad content
72
+ * @since 1.0.0
73
+ */
74
+ public function sanitize_content($content = ''){
75
+
76
+ // remove slashes from content
77
+ $content = wp_unslash($content);
78
+
79
+ // use WordPress core content filter
80
+ return $content = apply_filters('content_save_pre', $content);
81
+ }
82
+
83
+ }
classes/ad_type_plain.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Advanced Ads Plain Ad Type
4
+ *
5
+ * @package Advanced_Ads
6
+ * @author Thomas Maier <thomas.maier@webgilde.com>
7
+ * @license GPL-2.0+
8
+ * @link http://webgilde.com
9
+ * @copyright 2014 Thomas Maier, webgilde GmbH
10
+ *
11
+ * Class containing information about the plain text/code ad type
12
+ *
13
+ * see ad-type-content.php for a better sample on ad type
14
+ *
15
+ */
16
+ class Advads_Ad_Type_Plain extends Advads_Ad_Type_Abstract{
17
+
18
+ /**
19
+ * ID - internal type of the ad type
20
+ * *
21
+ * @since 1.0.0
22
+ */
23
+ public $ID = 'plain';
24
+
25
+ /**
26
+ * set basic attributes
27
+ *
28
+ * @since 1.0.0
29
+ */
30
+ public function __construct() {
31
+ $this->title = __('Plain Text and Code', Advanced_Ads::TD);
32
+ $this->description = __('Simple text editor without any filters. You might use it to display unfiltered content, php code or javascript. Shortcodes and other WordPress content field magic does not work here.', Advanced_Ads::TD);
33
+ $this->parameters = array(
34
+ 'content' => ''
35
+ );
36
+ }
37
+
38
+ /**
39
+ * output for the ad parameters metabox
40
+ *
41
+ * this will be loaded using ajax when changing the ad type radio buttons
42
+ * echo the output right away here
43
+ * name parameters must be in the "advanced_ads" array
44
+ *
45
+ * @param obj $ad ad object
46
+ * @since 1.0.0
47
+ */
48
+ public function render_parameters($ad){
49
+ // load tinymc content exitor
50
+ $content = (isset($ad->content)) ? $ad->content : '';
51
+ /**
52
+ * build the tinymc editor
53
+ * @link http://codex.wordpress.org/Function_Reference/wp_editor
54
+ */
55
+ ?><p class="description"><?php _e('Insert plain text or code into this field.', Advanced_Ads::TD); ?></p>
56
+ <textarea id="advads-ad-content-plain" cols="40" rows="10" name="advanced_ad[content]"><?php echo $content; ?></textarea>
57
+ <?php
58
+ }
59
+
60
+ /**
61
+ * prepare the ads frontend output
62
+ *
63
+ * @param obj $ad ad object
64
+ * @return str $content ad content prepared for frontend output
65
+ * @since 1.0.0
66
+ */
67
+ public function prepare_output($ad){
68
+ // evaluate the code as php
69
+ ob_start();
70
+ eval('?>'.$ad->content);
71
+ $content = ob_get_clean();
72
+ return $content;
73
+ }
74
+
75
+ }
includes/array_ad_conditions.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * conditions under which to (not) show an ad
5
+ * I don’t like huge arrays like this to clutter my classes
6
+ * and anyway, this might be needed on multiple places
7
+ *
8
+ * at the bottom, you find a filter to be able to extend / remove your own elements
9
+ *
10
+ * elements
11
+ * key - internal id of the condition; needs to be unique, obviously
12
+ * label - title in the dashboard
13
+ * description - (optional) description displayed in the dashboard
14
+ * type - information / markup type
15
+ * idfield - input field for comma separated lists of ids
16
+ * radio - radio button
17
+ *
18
+ * note: ’idfield’ always has a {field}_not version that is created automatically and being its own condition
19
+ *
20
+ */
21
+
22
+ $advanced_ads_slug = Advanced_Ads::get_instance()->get_plugin_slug();
23
+
24
+ $advanced_ads_ad_conditions = array(
25
+ 'postids' => array(
26
+ 'label' => __('Single Pages/Posts', $advanced_ads_slug),
27
+ 'description' => __('comma seperated IDs of post, page or custom post type', $advanced_ads_slug),
28
+ 'type' => 'idfield',
29
+ ),
30
+ 'categoryids' => array(
31
+ 'label' => __('Categories', $advanced_ads_slug),
32
+ 'description' => __('comma seperated IDs of categories for posts or category archives', $advanced_ads_slug),
33
+ 'type' => 'idfield',
34
+ ),
35
+ 'categoryarchiveids' => array(
36
+ 'label' => __('Category Archives', $advanced_ads_slug),
37
+ 'description' => __('comma seperated IDs of category archives', $advanced_ads_slug),
38
+ 'type' => 'idfield',
39
+ ),
40
+ 'posttypes' => array(
41
+ 'label' => __('Post Types', $advanced_ads_slug),
42
+ 'description' => __('comma seperated list of post types', $advanced_ads_slug),
43
+ 'type' => 'textvalues',
44
+ ),
45
+ 'is_front_page' => array(
46
+ 'label' => __('Home Page', $advanced_ads_slug),
47
+ 'description' => __('(don’t) show on Home page', $advanced_ads_slug),
48
+ 'type' => 'radio',
49
+ ),
50
+ 'is_singular' => array(
51
+ 'label' => __('Singular Pages', $advanced_ads_slug),
52
+ 'description' => __('(don’t) show on singular pages/posts', $advanced_ads_slug),
53
+ 'type' => 'radio',
54
+ ),
55
+ 'is_archive' => array(
56
+ 'label' => __('Archive Pages', $advanced_ads_slug),
57
+ 'description' => __('(don’t) show on any type of archive page (category, tag, author and date)', $advanced_ads_slug),
58
+ 'type' => 'radio',
59
+ ),
60
+ 'is_search' => array(
61
+ 'label' => __('Search Results', $advanced_ads_slug),
62
+ 'description' => __('(don’t) show on search result pages', $advanced_ads_slug),
63
+ 'type' => 'radio',
64
+ ),
65
+ 'is_404' => array(
66
+ 'label' => __('404 Page', $advanced_ads_slug),
67
+ 'description' => __('(don’t) show on 404 error page', $advanced_ads_slug),
68
+ 'type' => 'radio',
69
+ ),
70
+ 'is_attachment' => array(
71
+ 'label' => __('Attachment Pages', $advanced_ads_slug),
72
+ 'description' => __('(don’t) show on attachment pages', $advanced_ads_slug),
73
+ 'type' => 'radio',
74
+ )
75
+ );
76
+
77
+ $advanced_ads_ad_conditions = apply_filters('advanced-ads-conditions', $advanced_ads_ad_conditions);
includes/autoloader.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * autoloader
5
+ *
6
+ * currently all classes of real objects (e.g. ads) can be found in /classes on the plugins root directory
7
+ * all classes have the "Advads_" prefix to prevent any conflicts with other plugins
8
+ * but filenames don’t use "advads" and are written in lower case
9
+ * e.g. Advads_Ad is in file classes/ad.php
10
+ *
11
+ * to be able to change this structure later, I use an autoloader here
12
+ */
13
+ class Advads_Autoloader {
14
+
15
+ public static function load($classname) {
16
+ // to lower case
17
+ $classname = strtolower($classname);
18
+
19
+ // strip "advads_" prefix
20
+ $classname = str_replace('advads_', '', $classname);
21
+
22
+ $filepath = ADVADS_BASE_PATH . 'classes' . DIRECTORY_SEPARATOR . $classname . '.php';
23
+
24
+ if (file_exists($filepath)) {
25
+ require_once $filepath;
26
+ } else {
27
+ return false;
28
+ }
29
+ }
30
+
31
+ }
includes/class_ajax_callbacks.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Advanced Ads.
5
+ *
6
+ * @package Advanced_Ads
7
+ * @author Thomas Maier <thomas.maier@webgilde.com>
8
+ * @license GPL-2.0+
9
+ * @link http://webgilde.com
10
+ * @copyright 2013 Thomas Maier, webgilde GmbH
11
+ */
12
+
13
+ /**
14
+ * This class is used to bundle all ajax callbacks
15
+ *
16
+ * @package Advanced_Ads_Ajax_Callbacks
17
+ * @author Thomas Maier <thomas.maier@webgilde.com>
18
+ */
19
+ class Advanced_Ads_Ajax_Callbacks {
20
+
21
+ public function __construct() {
22
+
23
+ add_action( 'wp_ajax_load_content_editor', array( $this, 'load_content_editor' ) );
24
+ add_action( 'wp_ajax_load_ad_parameters_metabox', array( $this, 'load_ad_parameters_metabox' ) );
25
+ add_action( 'wp_ajax_advads-ad-group-ads-form', array( $this, 'load_ad_groups_ad_form' ) );
26
+ add_action( 'wp_ajax_advads-ad-group-ads-form-save', array( $this, 'save_ad_groups_ad_form' ) );
27
+
28
+ }
29
+
30
+ /**
31
+ * load content of the ad parameter metabox
32
+ *
33
+ * @since 1.0.0
34
+ */
35
+ public function load_ad_parameters_metabox() {
36
+
37
+ $types = Advanced_Ads::get_instance()->ad_types;
38
+ $type = $_REQUEST['ad_type'];
39
+ $ad_id = absint($_REQUEST['ad_id']);
40
+ if(empty($ad_id)) wp_die();
41
+
42
+ $ad = new Advads_Ad($ad_id);
43
+
44
+ if(!empty($types[$type]) && method_exists($types[$type], 'render_parameters')) {
45
+ $types[$type]->render_parameters($ad);
46
+ }
47
+
48
+ wp_die();
49
+
50
+ }
51
+
52
+ /**
53
+ * load the form to edit ads in an ad group
54
+ *
55
+ * @since 1.0.0
56
+ */
57
+ public function load_ad_groups_ad_form(){
58
+ $id = absint($_POST['group_id']);
59
+ // load the group
60
+ $group = new Advads_Ad_Group($id);
61
+ // get weights
62
+ $weights = $group->get_ad_weights();
63
+ // get group ads
64
+ $ads = $group->get_all_ads();
65
+
66
+ include_once(ADVADS_BASE_PATH . 'admin/views/ad-group-ads-inline-form.php');
67
+ die();
68
+ }
69
+
70
+ /**
71
+ * save
72
+ *
73
+ * @since 1.0.0
74
+ */
75
+ public function save_ad_groups_ad_form(){
76
+
77
+ // load field values
78
+ $fields = array();
79
+ parse_str($_POST['fields'], $fields);
80
+
81
+ if(!wp_verify_nonce($fields['advads-ad-groups-inline-form-nonce'], 'ad-groups-inline-edit-nonce')) die();
82
+
83
+ // load the group
84
+ $id = absint($_POST['group_id']);
85
+ $group = new Advads_Ad_Group($id);
86
+
87
+ if(!isset($fields['weight'])) die();
88
+ $group->save_ad_weights($fields['weight']);
89
+
90
+ // returning the weights as an array
91
+ header('Content-Type: application/json');
92
+ echo json_encode($group->get_ad_weights());
93
+
94
+ die();
95
+ }
96
+
97
+ }
98
+
99
+ $advanced_ads_ajax_calls = new Advanced_Ads_Ajax_Callbacks;
includes/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php // Silence is golden
index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php // Silence is golden
languages/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php // Silence is golden
languages/plugin-name.pot ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2013 Thomas Maier, webgilde.com
2
+ # This file is distributed under the same license as the Advanced_Ads package.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: TODO 1.0.0\n"
6
+ "Report-Msgid-Bugs-To: http://wordpress.org/plugins/plugin-name\n"
7
+ "POT-Creation-Date: 2013-05-10 11:23:19+00:00\n"
8
+ "PO-Revision-Date: 2013-05-10 10:37-0500\n"
9
+ "Last-Translator: FULL NAME <email@example.com>\n"
10
+ "Language-Team: LANGUAGE <translations@example.com >\n"
11
+ "MIME-Version: 1.0\n"
12
+ "Content-Type: text/plain; charset=UTF-8\n"
13
+ "Content-Transfer-Encoding: 8bit\n"
14
+ "X-Generator: Poedit 1.5.7\n"
15
+ "X-Poedit-KeywordsList: __;_e;_n;_x;esc_html_e;esc_html__;esc_attr_e;"
16
+ "esc_attr__;_ex:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2;_x:1,2c;_n:1,2\n"
17
+ "X-Poedit-Basepath: ../\n"
18
+ "Plural-Forms: nplurals=2; plural=n != 1;\n"
19
+ "X-Poedit-SearchPath-0: .\n"
20
+
21
+ #: class-plugin-name-admin.php:170
22
+ msgid "Page Title"
23
+ msgstr ""
24
+
25
+ #: class-plugin-name-admin.php:171
26
+ msgid "Menu Text"
27
+ msgstr ""
28
+
29
+ #: class-plugin-name-admin.php:197
30
+ msgid "Settings"
31
+ msgstr ""
public/assets/css/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php // Silence is golden
public/assets/css/public.css ADDED
@@ -0,0 +1 @@
 
1
+ /* This stylesheet is used to style the public-facing components of the plugin. */
public/assets/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php // Silence is golden
public/assets/js/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php // Silence is golden
public/assets/js/public.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ (function ( $ ) {
2
+ "use strict";
3
+
4
+ $(function () {
5
+
6
+ // Place your public-facing JavaScript here
7
+
8
+ });
9
+
10
+ }(jQuery));
public/class-advanced-ads.php ADDED
@@ -0,0 +1,553 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Advanced Ads.
5
+ *
6
+ * @package Advanced_Ads_Admin
7
+ * @author Thomas Maier <thomas.maier@webgilde.com>
8
+ * @license GPL-2.0+
9
+ * @link http://webgilde.com
10
+ * @copyright 2013 Thomas Maier, webgilde GmbH
11
+ */
12
+
13
+ /**
14
+ * Plugin class. This class should ideally be used to work with the
15
+ * public-facing side of the WordPress site.
16
+ *
17
+ * @package Advanced_Ads
18
+ * @author Thomas Maier <thomas.maier@webgilde.com>
19
+ */
20
+ class Advanced_Ads {
21
+ /**
22
+ * Plugin version, used for cache-busting of style and script file references.
23
+ *
24
+ * @since 1.0.0
25
+ * @var string
26
+ */
27
+
28
+ const VERSION = '1.0.0';
29
+
30
+ /**
31
+ * post type slug
32
+ *
33
+ * @since 1.0.0
34
+ * @var string
35
+ */
36
+ const POST_TYPE_SLUG = 'advanced_ads';
37
+
38
+ /**
39
+ * text domain
40
+ *
41
+ * @since 1.0.0
42
+ * @var string
43
+ */
44
+ const TD = 'advanced-ads';
45
+
46
+ /**
47
+ * ad group slug
48
+ *
49
+ * @since 1.0.0
50
+ * @var string
51
+ */
52
+ const AD_GROUP_TAXONOMY = 'advanced_ads_groups';
53
+
54
+ /**
55
+ * general plugin slug
56
+ *
57
+ * DEPRECATED: The variable name is used as the text domain when internationalizing strings
58
+ * of text. Its value should match the Text Domain file header in the main
59
+ * plugin file.
60
+ *
61
+ * @since 1.0.0
62
+ * @var string
63
+ */
64
+ protected $plugin_slug = 'advanced-ads';
65
+
66
+ /**
67
+ * Instance of this class.
68
+ *
69
+ * @since 1.0.0
70
+ * @var object
71
+ */
72
+ protected static $instance = null;
73
+
74
+ /**
75
+ * ad types
76
+ */
77
+ public $ad_types = array();
78
+
79
+ /**
80
+ * plugin options
81
+ *
82
+ * @since 1.0.1
83
+ * @var array (if loaded)
84
+ */
85
+ protected $options = false;
86
+
87
+ /**
88
+ * Initialize the plugin by setting localization and loading public scripts
89
+ * and styles.
90
+ *
91
+ * @since 1.0.0
92
+ */
93
+ private function __construct() {
94
+
95
+ // Load plugin text domain
96
+ add_action('init', array($this, 'load_plugin_textdomain'));
97
+
98
+ // activate plugin when new blog is added on multisites
99
+ add_action('wpmu_new_blog', array($this, 'activate_new_site'));
100
+
101
+ // Load public-facing style sheet and JavaScript.
102
+ add_action('wp_enqueue_scripts', array($this, 'enqueue_styles'));
103
+ add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));
104
+
105
+ // initialize plugin specific functions
106
+ add_action( 'init', array( $this, 'init' ) );
107
+ register_activation_hook(__FILE__, array($this,'post_types_rewrite_flush'));
108
+
109
+ // add short codes
110
+ add_shortcode('the_ad', array($this, 'shortcode_display_ad'));
111
+ add_shortcode('the_ad_group', array($this, 'shortcode_display_ad_group'));
112
+ // remove default ad group menu item
113
+ add_action('admin_menu', array($this, 'remove_taxonomy_menu_item'));
114
+
115
+ // setup default ad types
116
+ add_filter('advanced-ads-ad-types', array($this, 'setup_default_ad_types'));
117
+ }
118
+
119
+ /**
120
+ * init / load plugin specific functions and settings
121
+ *
122
+ * @since 1.0.0
123
+ */
124
+ public function init(){
125
+ // load ad post types
126
+ $this->create_post_types();
127
+ // set ad types array
128
+ $this->set_ad_types();
129
+ }
130
+
131
+ /**
132
+ * Return the plugin slug.
133
+ *
134
+ * @since 1.0.0
135
+ * @return Plugin slug variable.
136
+ */
137
+ public function get_plugin_slug() {
138
+ return $this->plugin_slug;
139
+ }
140
+
141
+ /**
142
+ * Return an instance of this class.
143
+ *
144
+ * @since 1.0.0
145
+ * @return object A single instance of this class.
146
+ */
147
+ public static function get_instance() {
148
+
149
+ // If the single instance hasn't been set, set it now.
150
+ if (null == self::$instance) {
151
+ self::$instance = new self;
152
+ }
153
+
154
+ return self::$instance;
155
+ }
156
+
157
+ /**
158
+ * Fired when the plugin is activated.
159
+ *
160
+ * @since 1.0.0
161
+ * @param boolean $network_wide True if WPMU superadmin uses
162
+ * "Network Activate" action, false if
163
+ * WPMU is disabled or plugin is
164
+ * activated on an individual blog.
165
+ */
166
+ public static function activate($network_wide) {
167
+
168
+ if (function_exists('is_multisite') && is_multisite()) {
169
+
170
+ if ($network_wide) {
171
+
172
+ // Get all blog ids
173
+ $blog_ids = self::get_blog_ids();
174
+
175
+ foreach ($blog_ids as $blog_id) {
176
+
177
+ switch_to_blog($blog_id);
178
+ self::single_activate();
179
+ }
180
+
181
+ restore_current_blog();
182
+ } else {
183
+ self::single_activate();
184
+ }
185
+ } else {
186
+ self::single_activate();
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Fired when the plugin is deactivated.
192
+ *
193
+ * @since 1.0.0
194
+ * @param boolean $network_wide
195
+ *
196
+ * True if WPMU superadmin uses
197
+ * "Network Deactivate" action, false if
198
+ * WPMU is disabled or plugin is
199
+ * deactivated on an individual blog.
200
+ */
201
+ public static function deactivate($network_wide) {
202
+
203
+ if (function_exists('is_multisite') && is_multisite()) {
204
+
205
+ if ($network_wide) {
206
+
207
+ // Get all blog ids
208
+ $blog_ids = self::get_blog_ids();
209
+
210
+ foreach ($blog_ids as $blog_id) {
211
+
212
+ switch_to_blog($blog_id);
213
+ self::single_deactivate();
214
+ }
215
+
216
+ restore_current_blog();
217
+ } else {
218
+ self::single_deactivate();
219
+ }
220
+ } else {
221
+ self::single_deactivate();
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Fired when a new site is activated with a WPMU environment.
227
+ *
228
+ * @since 1.0.0
229
+ * @param int $blog_id ID of the new blog.
230
+ */
231
+ public function activate_new_site($blog_id) {
232
+
233
+ if (1 !== did_action('wpmu_new_blog')) {
234
+ return;
235
+ }
236
+
237
+ switch_to_blog($blog_id);
238
+ self::single_activate();
239
+ restore_current_blog();
240
+ }
241
+
242
+ /**
243
+ * Get all blog ids of blogs in the current network that are:
244
+ * - not archived
245
+ * - not spam
246
+ * - not deleted
247
+ *
248
+ * @since 1.0.0
249
+ * @return array|false The blog ids, false if no matches.
250
+ */
251
+ private static function get_blog_ids() {
252
+
253
+ global $wpdb;
254
+
255
+ // get an array of blog ids
256
+ $sql = "SELECT blog_id FROM $wpdb->blogs
257
+ WHERE archived = '0' AND spam = '0'
258
+ AND deleted = '0'";
259
+
260
+ return $wpdb->get_col($sql);
261
+ }
262
+
263
+ /**
264
+ * Fired for each blog when the plugin is activated.
265
+ *
266
+ * @since 1.0.0
267
+ */
268
+ private static function single_activate() {
269
+ // @TODO: Define activation functionality here
270
+ }
271
+
272
+ /**
273
+ * Fired for each blog when the plugin is deactivated.
274
+ *
275
+ * @since 1.0.0
276
+ */
277
+ private static function single_deactivate() {
278
+ // @TODO: Define deactivation functionality here
279
+ }
280
+
281
+ /**
282
+ * Load the plugin text domain for translation.
283
+ *
284
+ * @since 1.0.0
285
+ */
286
+ public function load_plugin_textdomain() {
287
+
288
+ $domain = self::TD;
289
+ $locale = apply_filters('advanced-ads-plugin-locale', get_locale(), $domain);
290
+
291
+ load_textdomain($domain, trailingslashit(WP_LANG_DIR) . $domain . '/' . $domain . '-' . $locale . '.mo');
292
+ }
293
+
294
+ /**
295
+ * Register and enqueue public-facing style sheet.
296
+ *
297
+ * @since 1.0.0
298
+ */
299
+ public function enqueue_styles() {
300
+ wp_enqueue_style($this->plugin_slug . '-plugin-styles', plugins_url('assets/css/public.css', __FILE__), array(), self::VERSION);
301
+ }
302
+
303
+ /**
304
+ * Register and enqueues public-facing JavaScript files.
305
+ *
306
+ * @since 1.0.0
307
+ */
308
+ public function enqueue_scripts() {
309
+ wp_enqueue_script($this->plugin_slug . '-plugin-script', plugins_url('assets/js/public.js', __FILE__), array('jquery'), self::VERSION);
310
+ }
311
+
312
+ /**
313
+ * define ad types with their options
314
+ *
315
+ * name => publically readable name
316
+ * description => publically readable description
317
+ * editor => kind of editor: text (normal text field), content (WP content field), none (no content field)
318
+ * will display text field, if left empty
319
+ *
320
+ * @since 1.0.0
321
+ */
322
+ public function set_ad_types() {
323
+
324
+ /**
325
+ * load default ad type files
326
+ * custom ad types can also be loaded in your own plugin or functions.php
327
+ */
328
+ $types = array();
329
+
330
+ /**
331
+ * developers can add new ad types using this filter
332
+ * see classes/ad-type-content.php for an example for an ad type and usage of this filter
333
+ */
334
+ $this->ad_types = apply_filters('advanced-ads-ad-types', $types);
335
+ }
336
+
337
+ /**
338
+ * add plain and content ad types to the default ads of the plugin using a filter
339
+ *
340
+ * @since 1.0.0
341
+ *
342
+ */
343
+ function setup_default_ad_types($types){
344
+ $types['plain'] = new Advads_Ad_Type_Plain(); /* plain text and php code */
345
+ // $types['content'] = new Advads_Ad_Type_Content(); /* rich content editor */
346
+ return $types;
347
+ }
348
+
349
+ /**
350
+ * get an array with all ads by conditions
351
+ * = list possible ads for each condition
352
+ *
353
+ * @since 1.0.0
354
+ * @return arr $ads_by_conditions
355
+ */
356
+ public function get_ads_by_conditions_array(){
357
+
358
+ $ads_by_conditions = get_option('advads-ads-by-conditions', array());
359
+ // load default array if no conditions saved yet
360
+ if(!is_array($ads_by_conditions)){
361
+ $ads_by_conditions = array();
362
+ }
363
+
364
+ // load conditions from options
365
+ return $ads_by_conditions;
366
+ }
367
+
368
+ /**
369
+ * shortcode to include ad in frontend
370
+ *
371
+ * @since 1.0.0
372
+ * @param arr $atts
373
+ */
374
+ public function shortcode_display_ad($atts){
375
+ extract( shortcode_atts( array(
376
+ 'id' => 0,
377
+ ), $atts ) );
378
+
379
+ // use the public available function here
380
+ return get_ad($id);
381
+ }
382
+
383
+ /**
384
+ * shortcode to include ad from an ad group in frontend
385
+ *
386
+ * @since 1.0.0
387
+ * @param arr $atts
388
+ */
389
+ public function shortcode_display_ad_group($atts){
390
+ extract( shortcode_atts( array(
391
+ 'id' => 0,
392
+ ), $atts ) );
393
+
394
+ // use the public available function here
395
+ return get_ad_group($id);
396
+ }
397
+
398
+ /**
399
+ * Registers ad post type and group taxonomies
400
+ *
401
+ * @since 1.0.0
402
+ */
403
+ public function create_post_types() {
404
+ if (did_action('init') !== 1) {
405
+ return;
406
+ }
407
+
408
+ // register ad group taxonomy
409
+ if(!taxonomy_exists(self::AD_GROUP_TAXONOMY)){
410
+ $post_type_params = $this->get_group_taxonomy_params();
411
+ register_taxonomy(self::AD_GROUP_TAXONOMY, array(self::POST_TYPE_SLUG), $post_type_params);
412
+ }
413
+
414
+ // register ad post type
415
+ if (!post_type_exists(self::POST_TYPE_SLUG)) {
416
+ $post_type_params = $this->get_post_type_params();
417
+ register_post_type(self::POST_TYPE_SLUG, $post_type_params);
418
+ }
419
+ }
420
+
421
+ /**
422
+ * Defines the parameters for the ad post type taxonomy
423
+ *
424
+ * @since 1.0.0
425
+ * @return array
426
+ */
427
+ protected function get_group_taxonomy_params(){
428
+ $labels = array(
429
+ 'name' => _x('Ad Groups', 'ad group general name', $this->plugin_slug),
430
+ 'singular_name' => _x('Ad Group', 'ad group singular name', $this->plugin_slug),
431
+ 'search_items' => __('Search Ad Groups', $this->plugin_slug),
432
+ 'all_items' => __('All Ad Groups', $this->plugin_slug),
433
+ 'parent_item' => __('Parent Ad Groups', $this->plugin_slug),
434
+ 'parent_item_colon' => __('Parent Ad Groups:', $this->plugin_slug),
435
+ 'edit_item' => __('Edit Ad Group', $this->plugin_slug),
436
+ 'update_item' => __('Update Ad Group', $this->plugin_slug),
437
+ 'add_new_item' => __('Add New Ad Group', $this->plugin_slug),
438
+ 'new_item_name' => __('New Ad Groups Name', $this->plugin_slug),
439
+ 'menu_name' => __('Ad Groups', $this->plugin_slug),
440
+ 'not_found' => __('No Ad Group found', $this->plugin_slug),
441
+ );
442
+
443
+ $args = array(
444
+ 'hierarchical' => true,
445
+ 'labels' => $labels,
446
+ 'show_ui' => true,
447
+ 'show_in_nav_menus' => false,
448
+ 'show_tagcloud' => false,
449
+ 'show_admin_column' => false,
450
+ 'query_var' => true,
451
+ 'rewrite' => false,
452
+ );
453
+
454
+ return $args;
455
+ }
456
+
457
+ /**
458
+ * Defines the parameters for the custom post type
459
+ *
460
+ * @since 1.0.0
461
+ * @return array
462
+ */
463
+ protected function get_post_type_params() {
464
+ $labels = array(
465
+ 'name' => __('Ads', $this->plugin_slug),
466
+ 'singular_name' => __('Ad', $this->plugin_slug),
467
+ 'add_new' => 'Add New',
468
+ 'add_new_item' => __('Add New Ad', $this->plugin_slug),
469
+ 'edit' => __('Edit', $this->plugin_slug),
470
+ 'edit_item' => __('Edit Ad', $this->plugin_slug),
471
+ 'new_item' => __('New Ad', $this->plugin_slug),
472
+ 'view' => __('View', $this->plugin_slug),
473
+ 'view_item' => __('View the Ad', $this->plugin_slug),
474
+ 'search_items' => __('Search Ads', $this->plugin_slug),
475
+ 'not_found' => __('No Ads found', $this->plugin_slug),
476
+ 'not_found_in_trash' => __('No Ads found in Trash', $this->plugin_slug),
477
+ 'parent' => __('Parent Ad', $this->plugin_slug),
478
+ );
479
+
480
+ $post_type_params = array(
481
+ 'labels' => $labels,
482
+ 'singular_label' => __('Ad', $this->plugin_slug),
483
+ 'public' => false,
484
+ 'show_ui' => true,
485
+ 'menu_position' => 50, // above first seperator
486
+ 'hierarchical' => false,
487
+ 'capability_type' => 'page',
488
+ 'has_archive' => false,
489
+ 'rewrite' => array('slug' => $this->plugin_slug),
490
+ 'query_var' => true,
491
+ 'supports' => array('title'),
492
+ 'taxonomies' => array(self::AD_GROUP_TAXONOMY)
493
+ );
494
+
495
+ return apply_filters('advanced-ads-post-type-params', $post_type_params);
496
+ }
497
+
498
+ /**
499
+ * remove WP tag edit page for the ad group taxonomy
500
+ * needed, because we can’t remove it with `show_ui` without also removing the meta box
501
+ *
502
+ * @since 1.0.0
503
+ */
504
+ public function remove_taxonomy_menu_item() {
505
+ remove_submenu_page( 'edit.php?post_type=advanced_ads', 'edit-tags.php?taxonomy=advanced_ads_groups&amp;post_type=advanced_ads' );
506
+ }
507
+
508
+ /**
509
+ * flush rewrites on plugin activation so permalinks for them work from the beginning on
510
+ *
511
+ * @since 1.0.0
512
+ * @link http://codex.wordpress.org/Function_Reference/register_post_type#Flushing_Rewrite_on_Activation
513
+ */
514
+ public function post_types_rewrite_flush(){
515
+ // load custom post type
516
+ $this->create_post_types();
517
+ // flush rewrite rules
518
+ flush_rewrite_rules();
519
+ }
520
+
521
+ /**
522
+ * log error messages when debug is enabled
523
+ *
524
+ * @since 1.0.0
525
+ * @link http://www.smashingmagazine.com/2011/03/08/ten-things-every-wordpress-plugin-developer-should-know/
526
+ */
527
+ public function log($message) {
528
+ if (WP_DEBUG === true) {
529
+ if (is_array($message) || is_object($message)) {
530
+ error_log('Advanced Ads Error following:', $this->plugin_slug);
531
+ error_log(print_r($message, true));
532
+ } else {
533
+ $message = sprintf(__('Advanced Ads Error: %s', $this->plugin_slug), $message);
534
+ error_log($message);
535
+ }
536
+ }
537
+ }
538
+
539
+ /**
540
+ * return plugin options
541
+ *
542
+ * @since 1.0.1
543
+ * @return arr $options
544
+ * @todo parse default options
545
+ */
546
+ public function options(){
547
+ if($this->options === false){
548
+ $this->options = get_option(ADVADS_SLUG, array());
549
+ }
550
+
551
+ return $this->options;
552
+ }
553
+ }
public/functions.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * functions that are directly available in WordPress themes (and plugins)
5
+ */
6
+
7
+ /**
8
+ * return ad content
9
+ *
10
+ * @since 1.0.0
11
+ * @param int $id id of the ad (post)
12
+ *
13
+ */
14
+ function get_ad($id = 0){
15
+ $id = absint($id);
16
+ if(empty($id)) return;
17
+
18
+ // get ad
19
+ $ad = new Advads_Ad($id);
20
+
21
+ // check conditions
22
+ if($ad->can_display())
23
+ return $ad->output();
24
+ }
25
+
26
+ /**
27
+ * echo an ad
28
+ *
29
+ * @since 1.0.0
30
+ * @param int $id id of the ad (post)
31
+ */
32
+ function the_ad($id = 0){
33
+
34
+ echo get_ad($id);
35
+
36
+ }
37
+
38
+ /**
39
+ * return an ad from an ad group based on ad weight
40
+ *
41
+ * @since 1.0.0
42
+ * @param int $id id of the ad group (taxonomy)
43
+ *
44
+ */
45
+ function get_ad_group($id = 0){
46
+ $id = absint($id);
47
+ if(empty($id)) return;
48
+
49
+ // get ad
50
+ $adgroup = new Advads_Ad_Group($id);
51
+ return $adgroup->output_random_ad();
52
+ }
53
+
54
+ /**
55
+ * echo an ad from an ad group
56
+ *
57
+ * @since 1.0.0
58
+ * @param int $id id of the ad (post)
59
+ */
60
+ function the_ad_group($id = 0){
61
+
62
+ echo get_ad_group($id);
63
+
64
+ }
public/includes/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php // Silence is golden
public/views/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php // Silence is golden
public/views/public.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Represents the view for the public-facing component of the plugin.
4
+ *
5
+ * This typically includes any information, if any, that is rendered to the
6
+ * frontend of the theme when the plugin is activated.
7
+ *
8
+ * @package Plugin_Name
9
+ * @author Your Name <email@example.com>
10
+ * @license GPL-2.0+
11
+ * @link http://example.com
12
+ * @copyright 2013 Your Name or Company Name
13
+ */
14
+ ?>
15
+
16
+ <!-- This file is used to markup the public facing aspect of the plugin. -->
uninstall.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Fired when the plugin is uninstalled.
4
+ *
5
+ * @package Plugin_Name
6
+ * @author Your Name <email@example.com>
7
+ * @license GPL-2.0+
8
+ * @link http://example.com
9
+ * @copyright 2013 Your Name or Company Name
10
+ */
11
+
12
+ // If uninstall not called from WordPress, then exit
13
+ if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
14
+ exit;
15
+ }
16
+
17
+ // @TODO: Define uninstall functionality here