Attachments - Version 3.0.6

Version Description

  • Fixed a possible JavaScript error if an Attachment that's an image doesn't have a proper thumbnail URL
  • Added a total() method that will return the number of Attachments for the current instance
  • When requesting the image() for a non-image Attachment, the WordPress-defined icon will be returned
  • Added an icon() method that will return the WordPress-defined icon for the Attachment
  • Cleaned up a PHP Warning when trying to save for an undefined field type
  • Fixed an issue where template tags would be output for non-image Attachments after saving
Download this release

Release Info

Developer jchristopher
Plugin Icon wp plugin Attachments
Version 3.0.6
Comparing to
See all releases

Code changes from version 1.6.2.1 to 3.0.6

Files changed (46) hide show
  1. CONTRIBUTING.md +14 -0
  2. README.md +302 -0
  3. classes/class.attachments.php +1220 -0
  4. classes/class.field.php +85 -0
  5. classes/fields/class.field.text.php +35 -0
  6. classes/fields/index.php +1 -0
  7. classes/index.php +1 -0
  8. css/attachments.css +166 -73
  9. css/index.php +5 -0
  10. attachments.options.php → deprecated/attachments.options.php +0 -0
  11. attachments.php → deprecated/attachments.php +8 -109
  12. deprecated/css/attachments.css +73 -0
  13. deprecated/css/index.php +1 -0
  14. deprecated/get-attachments.php +105 -0
  15. deprecated/images/handle.gif +0 -0
  16. deprecated/images/index.php +1 -0
  17. deprecated/index.php +1 -0
  18. deprecated/js/attachments.js +146 -0
  19. {js → deprecated/js}/handlebars.js +0 -0
  20. deprecated/js/index.php +1 -0
  21. {languages → deprecated/languages}/attachments-fr_FR.mo +0 -0
  22. {languages → deprecated/languages}/attachments-fr_FR.po +0 -0
  23. {languages → deprecated/languages}/attachments-it_IT.mo +0 -0
  24. {languages → deprecated/languages}/attachments-it_IT.po +0 -0
  25. {languages → deprecated/languages}/attachments-pl_PL.mo +0 -0
  26. {languages → deprecated/languages}/attachments-pl_PL.po +0 -0
  27. {languages → deprecated/languages}/attachments-pt_BR.mo +0 -0
  28. {languages → deprecated/languages}/attachments-pt_BR.po +0 -0
  29. {languages → deprecated/languages}/attachments-sv_SE.mo +0 -0
  30. {languages → deprecated/languages}/attachments-sv_SE.po +0 -0
  31. deprecated/languages/index.php +1 -0
  32. humans.txt +16 -0
  33. images/handle.gif +0 -0
  34. images/index.php +5 -0
  35. index.php +47 -0
  36. js/attachments.js +86 -142
  37. js/index.php +5 -0
  38. languages/index.php +5 -0
  39. license.txt +281 -0
  40. readme.txt +216 -34
  41. screenshot-1.jpg +0 -0
  42. screenshot-2.jpg +0 -0
  43. screenshot-3.jpg +0 -0
  44. upgrade.php +3 -0
  45. views/index.php +1 -0
  46. views/options.php +274 -0
CONTRIBUTING.md ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Contributing to Attachments development
2
+
3
+ Thank you so much for contributing to this project, I love pull requests! To effecively contribute to the development of Attachments please do the following:
4
+
5
+ 1. Create a GitHub account
6
+ 1. [Fork](https://help.github.com/articles/fork-a-repo) the repo
7
+ 1. Create a branch from `master` with a meaningful name describing your task
8
+ 1. Ensure extrenuous whitespace is removed before committing
9
+ 1. Make commits of logical units
10
+ 1. Ensure commit messages effectively explain everything that was changed
11
+ 1. Push your changes to your branch of your fork
12
+ 1. Submit a pull request
13
+
14
+ Thank you!
README.md ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ This is a WordPress plugin. [Official download available on WordPress Extend](http://wordpress.org/extend/plugins/attachments/).
2
+
3
+ # Attachments
4
+
5
+ Attachments allows you to simply append any number of items from your WordPress Media Library to Posts, Pages, and Custom Post Types
6
+
7
+ * [Description](#description)
8
+ * [Installation](#installation)
9
+ * **[Upgrade Notice](#upgrade-notice)** *Pay specific attention if upgrading from a version before 3.0*
10
+ * [Usage](#usage)
11
+ * [Screenshots](#screenshots)
12
+ * [Frequently Asked Questions](#frequently-asked-questions)
13
+ * [Changelog](#changelog)
14
+ * [Roadmap](#roadmap)
15
+
16
+ ## Description
17
+
18
+ Attachments allows you to simply append any number of items from your WordPress Media Library to Posts, Pages, and Custom Post Types. This plugin *does not* directly interact with your theme, you will need to edit your template files.
19
+
20
+ ### Updated for WordPress 3.5!
21
+
22
+ WordPress 3.5 ships with an amazing new Media workflow and Attachments 3.0 makes great use of it. *If you are not running WordPress 3.5, version 1.6.2.1 will be used until you upgrade to WordPress 3.5.*
23
+
24
+ ### Associate Media items with posts
25
+
26
+ The idea behind Attachments is to give developers the ability to directly associate Media items with any post. This is accomplished by adding a meta box to post edit screens as determined by the developer. Once Media items have been associated with a post, you're able to retrieve those Attachments and include them directly within your template files using any specific markup you wish.
27
+
28
+ ### Integrate Attachments within your theme with fine grained control
29
+
30
+ **Attachments does not automatically integrate itself with your theme.** Since the idea behind Attachments is to allow integration of Media within posts using developer-crafted, unique markup, *it's up to you to integrate with your theme*. The most basic integration includes editing the [appropriate template file](http://codex.wordpress.org/Template_Hierarchy) and adding your call(s) to Attachments. For example, if you have set up Attachments to be used with your Posts entries, edit `single.php` to include the following within The Loop:
31
+
32
+ ```php
33
+ <?php $attachments = new Attachments( 'attachments' ); /* pass the instance name */ ?>
34
+ <?php if( $attachments->exist() ) : ?>
35
+ <h3>Attachments</h3>
36
+ <ul>
37
+ <?php while( $attachments->get() ) : ?>
38
+ <li>
39
+ ID: <?php echo $attachments->id(); ?><br />
40
+ Type: <?php echo $attachments->type(); ?><br />
41
+ Subtype: <?php echo $attachments->subtype(); ?><br />
42
+ URL: <?php echo $attachments->url(); ?><br />
43
+ Image: <?php echo $attachments->image( 'thumbnail' ); ?><br />
44
+ Source: <?php echo $attachments->src( 'full' ); ?><br />
45
+ Size: <?php echo $attachments->filesize(); ?><br />
46
+ Title Field: <?php echo $attachments->field( 'title' ); ?><br />
47
+ Caption Field: <?php echo $attachments->field( 'caption' ); ?>
48
+ </li>
49
+ <?php endwhile; ?>
50
+ </ul>
51
+ <?php endif; ?>
52
+ ```
53
+
54
+ That snippet will request all of the existing Attachments defined for the current Post within The Loop, and retrieve each itemized property for that Attachment. Using the provided details you're able to integrate the attached Media items in any way you please.
55
+
56
+ ## Installation
57
+
58
+ 1. Download the plugin and extract the files
59
+ 1. Upload `attachments` to your `~/wp-content/plugins/` directory
60
+ 1. Activate the plugin through the 'Plugins' menu in WordPress
61
+ 1. Implement Attachments in your theme's `functions.php` or your own plugin (see **[Usage](#usage)**)
62
+ 1. Update your templates where applicable (see **[Usage](#usage)**)
63
+
64
+ ## Upgrade Notice
65
+
66
+ #### 3.0
67
+ **You will need to update your theme files that use Attachments 3.0**. Version 1.x of Attachments has been *fully deprecated* but is still available. If you would like to continue to use the (no longer supported) 1.x version you may add the following to your `wp-config.php`:
68
+
69
+ ```php
70
+ define( 'ATTACHMENTS_LEGACY', true ); // force the legacy version of Attachments
71
+ ```
72
+
73
+ Version 3 is a **major** rewrite. While I've taken precautions in ensuring you won't lose any saved data it is important to back up your databse prior to upgrading in case something goes wrong. This version is a complete rewrite so all legacy data will be left in place, but a migration must take place to match the new data storage model and workflow.
74
+
75
+ ## Usage
76
+
77
+ When Attachments is first activated, a default instance is created titled Attachments. It has two fields:
78
+
79
+ 1. Title
80
+ 1. Caption
81
+
82
+ If you would like to *disable the default instance* (meta box titled 'Attachments' with a 'Title' and 'Caption' field) add the following to your `wp-config.php`:
83
+
84
+ ```php
85
+ define( 'ATTACHMENTS_DEFAULT_INSTANCE', false );
86
+ ```
87
+
88
+ You may create instances with your own custom fields by using the `attachments_register` action. To create your own instance add the following to your theme's `functions.php` or your own plugin:
89
+
90
+ ```php
91
+ <?php
92
+
93
+ function my_attachments( $attachments )
94
+ {
95
+ $args = array(
96
+
97
+ // title of the meta box (string)
98
+ 'label' => 'My Attachments',
99
+
100
+ // all post types to utilize (string|array)
101
+ 'post_type' => array( 'post', 'page' ),
102
+
103
+ // allowed file type(s) (array) (image|video|text|audio|application)
104
+ 'filetype' => null, // no filetype limit
105
+
106
+ // include a note within the meta box (string)
107
+ 'note' => 'Attach files here!',
108
+
109
+ // text for 'Attach' button (string)
110
+ 'button_text' => __( 'Attach Files', 'attachments' ),
111
+
112
+ // text for modal 'Attach' button (string)
113
+ 'modal_text' => __( 'Attach', 'attachments' ),
114
+
115
+ // fields for this instance (array)
116
+ 'fields' => array(
117
+ array(
118
+ 'name' => 'title', // unique field name
119
+ 'type' => 'text', // registered field type (field available in 3.0: text)
120
+ 'label' => __( 'Title', 'attachments' ), // label to display
121
+ ),
122
+ array(
123
+ 'name' => 'caption', // unique field name
124
+ 'type' => 'text', // registered field type (field available in 3.0: text)
125
+ 'label' => __( 'Caption', 'attachments' ), // label to display
126
+ ),
127
+ array(
128
+ 'name' => 'copyright', // unique field name
129
+ 'type' => 'text', // registered field type (field available in 3.0: text)
130
+ 'label' => __( 'Copyright', 'attachments' ), // label to display
131
+ ),
132
+ ),
133
+
134
+ );
135
+
136
+ $attachments->register( 'my_attachments', $args ); // unique instance name
137
+ }
138
+
139
+ add_action( 'attachments_register', 'my_attachments' );
140
+ ```
141
+
142
+ Once your instances are set up and working, you'll also need to edit your theme's template files to pull the data to the front end. To retrieve the Attachments for the current post, add this within The Loop:
143
+
144
+ ```php
145
+ <?php $attachments = new Attachments( 'attachments' ); /* pass the instance name */ ?>
146
+ <?php if( $attachments->exist() ) : ?>
147
+ <h3>Attachments</h3>
148
+ <ul>
149
+ <?php while( $attachment = $attachments->get() ) : ?>
150
+ <li>
151
+ <pre><?php print_r( $attachment ); ?></pre>
152
+ </li>
153
+ <?php endwhile; ?>
154
+ </ul>
155
+ <?php endif; ?>
156
+ ```
157
+
158
+ If you want to get the Attachments for a post **outside The Loop**, add a second parameter with the post ID when instantiating Attachments:
159
+
160
+ ```php
161
+ <?php
162
+ // retrieve all Attachments for the 'attachments' instance of post 123
163
+ $attachments = new Attachments( 'attachments', 123 );
164
+ ?>
165
+ <?php if( $attachments->exist() ) : ?>
166
+ <h3>Attachments</h3>
167
+ <ul>
168
+ <?php while( $attachment = $attachments->get() ) : ?>
169
+ <li>
170
+ <pre><?php print_r( $attachment ); ?></pre>
171
+ </li>
172
+ <?php endwhile; ?>
173
+ </ul>
174
+ <?php endif; ?>
175
+ ```
176
+
177
+ You can also retrieve various attributes of the current Attachment directly using these utility functions:
178
+
179
+ ```php
180
+ <?php $attachments = new Attachments( 'attachments' ); ?>
181
+ <?php if( $attachments->exist() ) : ?>
182
+ <h3>Attachments</h3>
183
+ <p>Total Attachments: <?php echo $attachments->total(); ?></p>
184
+ <ul>
185
+ <?php while( $attachments->get() ) : ?>
186
+ <li>
187
+ ID: <?php echo $attachments->id(); ?><br />
188
+ Type: <?php echo $attachments->type(); ?><br />
189
+ Subtype: <?php echo $attachments->subtype(); ?><br />
190
+ URL: <?php echo $attachments->url(); ?><br />
191
+ Image: <?php echo $attachments->image( 'thumbnail' ); ?><br />
192
+ Source: <?php echo $attachments->src( 'full' ); ?><br />
193
+ Size: <?php echo $attachments->filesize(); ?><br />
194
+ Title Field: <?php echo $attachments->field( 'title' ); ?><br />
195
+ Caption Field: Name: <?php echo $attachments->field( 'caption' ); ?>
196
+ </li>
197
+ <?php endwhile; ?>
198
+ </ul>
199
+ <?php endif; ?>
200
+ ```
201
+
202
+ ## Screenshots
203
+
204
+ ##### An Attachments meta box sitting below the content editor
205
+ ![An Attachments meta box sitting below the content editor](http://mondaybynoon.com/images/attachments/screenshot-1.png)
206
+
207
+ ##### Direct integration with WordPress 3.5+ Media
208
+ ![Direct integration with WordPress 3.5+ Media](http://mondaybynoon.com/images/attachments/screenshot-2.png)
209
+
210
+ ##### Attach multiple files at once
211
+ ![Attach multiple files at once](http://mondaybynoon.com/images/attachments/screenshot-3.png)
212
+
213
+ ##### Custom fields for each Attachment
214
+ ![Custom fields for each Attachment](http://mondaybynoon.com/images/attachments/screenshot-4.png)
215
+
216
+ ##### Drag and drop to sort
217
+ ![Drag and drop to sort](http://mondaybynoon.com/images/attachments/screenshot-5.png)
218
+
219
+ ## Frequently Asked Questions
220
+
221
+ #### Attachments isn't showing up on my edit screens
222
+
223
+ You will need to tell Attachments which instances you'd like to use. Please reference the **[Usage](#usage)** instructions.
224
+
225
+ #### Attachments are not showing up in my theme
226
+
227
+ You will need to edit your theme files where applicable. Please reference the **[Usage](#usage)** instructions.
228
+
229
+ #### How do I disable the default Attachments meta box?
230
+
231
+ You will need to edit your Attachments configuration. Please reference the **[Usage](#usage)** instructions.
232
+
233
+ #### How do I change the fields for each Attachment?
234
+
235
+ You will need to edit your Attachments configuration. Please reference the **[Usage](#usage)** instructions.
236
+
237
+ #### Where are uploads saved?
238
+
239
+ Attachments uses WordPress' built in Media library for uploads and storage.
240
+
241
+ #### I lost my Attachments after upgrading!
242
+
243
+ ***DO NOT update any Post/Page/CPT with Attachments***, the data has not been lost. Please [contact me](http://mondaybynoon.com/contact/) to begin a bugfix
244
+
245
+ ## Changelog
246
+
247
+ <dl>
248
+
249
+ <dt>3.0.6</dt>
250
+ <dd>Fixed a possible JavaScript error if an Attachment that's an image doesn't have a proper thumbnail URL</dd>
251
+ <dd>Added a total() method that will return the number of Attachments for the current instance</dd>
252
+ <dd>When requesting the image() for a non-image Attachment, the WordPress-defined icon will be returned</dd>
253
+ <dd>Added an icon() method that will return the WordPress-defined icon for the Attachment</dd>
254
+ <dd>Cleaned up a PHP Warning when trying to save for an undefined field type</dd>
255
+ <dd>Fixed an issue where template tags would be output for non-image Attachments after saving</dd>
256
+
257
+ <dt>3.0.5</dt>
258
+ <dd>Fixed a regression in handling Custom Post Type names that would too aggressively interfere with instance regustration</dd>
259
+ <dd>Fixed an issue when working with non-image Attachments</dd>
260
+
261
+ <dt>3.0.4</dt>
262
+ <dd>Fixed an issue that prevented the choosing of a Featured Image for a Custom Post Type if Attachments was activated</dd>
263
+ <dd>Attachments now only enqueues its assets on edit screens that actually utilize Attachments</dd>
264
+ <dd>Fixed a potential JavaScript error triggered when a 'thumbnail' image size was not available</dd>
265
+ <dd>Prevented incorrect usage of dashes used in CPT names for post_type argument when registering Attachments instances (fixes an integration issue with WP e-Commerce)</dd>
266
+ <dd>Prevented re-running of migration process to avoid duplicates (e.g. on browser reload)</dd>
267
+
268
+ <dt>3.0.3</dt>
269
+ <dd>Fixed an issue that prevented defining a post ID when retrieving Attachments outside The Loop</dd>
270
+ <dd>Cleaned up potential PHP warning when Attachments were requested for a post that had none</dd>
271
+
272
+ <dt>3.0.2</dt>
273
+ <dd>Fixed an issue where some HTML entities were not properly stored</dd>
274
+
275
+ <dt>3.0.1</dt>
276
+ <dd>Fixed an issue where legacy mode was always enabled</dd>
277
+
278
+ <dt>3.0</dt>
279
+ <dd> <strong>Major</strong> rewrite. After three years of development, Attachments has been rewritten to make
280
+ even better use of what WordPress has to offer</dd>
281
+ <dd> Utilizes the brand spanking new 3.5 Media workflow</dd>
282
+ <dd> Configuration now takes place within your theme or a plugin</dd>
283
+ <dd> Multiple meta boxes! You can segment groups of Attachments with new instances, each unique</dd>
284
+ <dd> Dynamic fields! You can manipulate which fields each instance uses</dd>
285
+ <dd> File type limits. Limit which files are available to Attachments (e.g. images, audio, video)</dd>
286
+
287
+ </dl>
288
+
289
+ ## Roadmap
290
+
291
+ Planned feature additions include:
292
+
293
+ * Additional field type: textarea
294
+ * Additional field type: WYSIWYG
295
+ * Additional field type: checkbox
296
+ * Additional field type: radio
297
+ * Additional field type: select
298
+ * User-defined limiting the number of Attachments per instance
299
+ * User-defined custom field types
300
+ * Additional hooks/actions from top to bottom
301
+ * Shortcode(s)
302
+ * Output templates
classes/class.attachments.php ADDED
@@ -0,0 +1,1220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Attachments
5
+ *
6
+ * Attachments allows you to simply append any number of items from your WordPress
7
+ * Media Library to Posts, Pages, and Custom Post Types
8
+ *
9
+ * @package Attachments
10
+ * @subpackage Main
11
+ */
12
+
13
+ // Exit if accessed directly
14
+ if( !defined( 'ABSPATH' ) ) exit;
15
+
16
+ // Declare our class
17
+ if ( !class_exists( 'Attachments' ) ) :
18
+
19
+ /**
20
+ * Main Attachments Class
21
+ *
22
+ * @since 3.0
23
+ */
24
+
25
+ class Attachments {
26
+
27
+ private $version; // stores Attachments' version number
28
+ private $url; // stores Attachments' URL
29
+ private $dir; // stores Attachments' directory
30
+ private $instances; // all registered Attachments instances
31
+ private $instances_for_post_type; // instance names that apply to the current post type
32
+ private $fields; // stores all registered field types
33
+ private $attachments; // stores all of the Attachments for the given instance
34
+
35
+ private $image_sizes = array( 'full' ); // store all registered image sizes
36
+ private $default_instance = true; // use the default instance?
37
+ private $attachments_ref = -1; // flags where a get() loop last did it's thing
38
+ private $meta_key = 'attachments'; // our meta key
39
+ private $valid_filetypes = array( // what WordPress considers to be valid file types
40
+ 'image',
41
+ 'video',
42
+ 'text',
43
+ 'audio',
44
+ 'application'
45
+ );
46
+
47
+
48
+
49
+ /**
50
+ * Constructor
51
+ *
52
+ * @since 3.0
53
+ */
54
+ function __construct( $instance = null, $post_id = null )
55
+ {
56
+ global $_wp_additional_image_sizes;
57
+
58
+ // establish our environment variables
59
+ $this->version = '3.0.6';
60
+ $this->url = ATTACHMENTS_URL;
61
+ $this->dir = ATTACHMENTS_DIR;
62
+
63
+ // includes
64
+ include_once( ATTACHMENTS_DIR . 'upgrade.php' );
65
+ include_once( ATTACHMENTS_DIR . '/classes/class.field.php' );
66
+
67
+ // deal with our legacy issues if the user hasn't dismissed or migrated already
68
+ if( false == get_option( 'attachments_migrated' ) && false == get_option( 'attachments_ignore_migration' ) )
69
+ {
70
+ $legacy = new WP_Query( 'post_type=any&post_status=any&posts_per_page=1&meta_key=_attachments' );
71
+ $this->legacy = empty( $legacy->found_posts ) ? false : true;
72
+ }
73
+ else
74
+ {
75
+ $this->legacy = false;
76
+ }
77
+
78
+ // set our image sizes
79
+ $this->image_sizes = array_merge( $this->image_sizes, get_intermediate_image_sizes() );
80
+
81
+ // include our fields
82
+ $this->fields = $this->get_field_types();
83
+
84
+ // hook into WP
85
+ add_action( 'admin_enqueue_scripts', array( $this, 'assets' ), 999, 1 );
86
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_pointer' ), 999 );
87
+
88
+ // register our user-defined instances
89
+ add_action( 'init', array( $this, 'do_actions_filters' ) );
90
+
91
+ // determine which instances apply to the current post type
92
+ add_action( 'init', array( $this, 'set_instances_for_current_post_type' ), 999 );
93
+
94
+ add_action( 'add_meta_boxes', array( $this, 'meta_box_init' ) );
95
+
96
+ add_action( 'admin_footer', array( $this, 'admin_footer' ) );
97
+
98
+ add_action( 'save_post', array( $this, 'save' ) );
99
+
100
+ add_action( 'admin_menu', array( $this, 'admin_page' ) );
101
+
102
+ // with version 3 we'll be giving at least one admin notice
103
+ add_action( 'admin_notices', array( $this, 'admin_notice' ) );
104
+
105
+ // set our attachments if necessary
106
+ if( !is_null( $instance ) )
107
+ $this->attachments = $this->get_attachments( $instance, $post_id );
108
+ }
109
+
110
+
111
+
112
+ /**
113
+ * Returns whether or not the current object has any Attachments
114
+ *
115
+ * @since 3.0
116
+ */
117
+ function exist()
118
+ {
119
+ return !empty( $this->attachments );
120
+ }
121
+
122
+
123
+
124
+ /**
125
+ * Returns the number of Attachments
126
+ *
127
+ * @since 3.0.6
128
+ */
129
+ function total()
130
+ {
131
+ return count( $this->attachments );
132
+ }
133
+
134
+
135
+
136
+ /**
137
+ * Returns the next Attachment for the current object and increments the index
138
+ *
139
+ * @since 3.0
140
+ */
141
+ function get()
142
+ {
143
+ $this->attachments_ref++;
144
+
145
+ if( !count( $this->attachments ) || $this->attachments_ref >= count( $this->attachments ) )
146
+ return false;
147
+
148
+ return $this->attachments[$this->attachments_ref];
149
+ }
150
+
151
+
152
+
153
+ /**
154
+ * Returns the asset (array) for the current Attachment
155
+ *
156
+ * @since 3.0.6
157
+ */
158
+ function asset( $size = 'thumbnail' )
159
+ {
160
+ // do we have our meta yet?
161
+ if( !isset( $this->attachments[$this->attachments_ref]->meta ) )
162
+ $this->attachments[$this->attachments_ref]->meta = wp_get_attachment_metadata( $this->attachments[$this->attachments_ref]->id );
163
+
164
+ // is it an image?
165
+ if(
166
+ isset( $this->attachments[$this->attachments_ref]->meta['sizes'] ) && // is it an image?
167
+ in_array( $size, $this->image_sizes ) ) // do we have the right size?
168
+ {
169
+ $asset = wp_get_attachment_image_src( $this->attachments[$this->attachments_ref]->id, $size );
170
+ }
171
+ else
172
+ {
173
+ // either it's not an image or we don't have the proper size, so we'll use the icon
174
+ $asset = $this->icon();
175
+ }
176
+
177
+ return $asset;
178
+ }
179
+
180
+
181
+
182
+ /**
183
+ * Returns the icon (array) for the current Attachment
184
+ *
185
+ * @since 3.0.6
186
+ */
187
+ function icon()
188
+ {
189
+ $asset = wp_get_attachment_image_src( $this->attachments[$this->attachments_ref]->id, null, true );
190
+ return $asset;
191
+ }
192
+
193
+
194
+
195
+ /**
196
+ * Returns an appropriate <img /> for the current Attachment if it's an image
197
+ *
198
+ * @since 3.0
199
+ */
200
+ function image( $size = 'thumbnail' )
201
+ {
202
+ $asset = $this->asset( $size );
203
+
204
+ $image_src = $asset[0];
205
+ $image_width = $asset[1];
206
+ $image_height = $asset[2];
207
+ $image_alt = get_post_meta( $this->attachments[$this->attachments_ref]->id, '_wp_attachment_image_alt', true );
208
+
209
+ $image = '<img src="' . $image_src . '" width="' . $image_width . '" height="' . $image_height . '" alt="' . $image_alt . '" />';
210
+
211
+ return $image;
212
+ }
213
+
214
+
215
+
216
+ /**
217
+ * Returns the URL for the current Attachment if it's an image
218
+ *
219
+ * @since 3.0
220
+ */
221
+ function src( $size = 'thumbnail' )
222
+ {
223
+ $asset = $this->asset( $size );
224
+ return $asset[0];
225
+ }
226
+
227
+
228
+
229
+ /**
230
+ * Returns the formatted filesize of the current Attachment
231
+ *
232
+ * @since 3.0
233
+ */
234
+ function filesize()
235
+ {
236
+ if( !isset( $this->attachments[$this->attachments_ref]->id ) )
237
+ return false;
238
+
239
+ $url = wp_get_attachment_url( $this->attachments[$this->attachments_ref]->id );
240
+ $uploads = wp_upload_dir();
241
+ $file_path = str_replace( $uploads['baseurl'], $uploads['basedir'], $url );
242
+
243
+ $formatted = '0 bytes';
244
+ if( file_exists( $file_path ) )
245
+ {
246
+ $formatted = size_format( @filesize( $file_path ) );
247
+ }
248
+ return $formatted;
249
+ }
250
+
251
+
252
+
253
+ /**
254
+ * Returns the type of the current Attachment
255
+ *
256
+ * @since 3.0
257
+ */
258
+ function type()
259
+ {
260
+ if( !isset( $this->attachments[$this->attachments_ref]->id ) )
261
+ return false;
262
+
263
+ $attachment_mime = explode( '/', get_post_mime_type( $this->attachments[$this->attachments_ref]->id ) );
264
+ return isset( $attachment_mime[0] ) ? $attachment_mime[0] : null;
265
+ }
266
+
267
+
268
+
269
+ /**
270
+ * Returns the subtype of the current Attachment
271
+ *
272
+ * @since 3.0
273
+ */
274
+ function subtype()
275
+ {
276
+ if( !isset( $this->attachments[$this->attachments_ref]->id ) )
277
+ return false;
278
+
279
+ $attachment_mime = explode( '/', get_post_mime_type( $this->attachments[$this->attachments_ref]->id ) );
280
+ return isset( $attachment_mime[1] ) ? $attachment_mime[1] : null;
281
+ }
282
+
283
+
284
+
285
+ /**
286
+ * Returns the id of the current Attachment
287
+ *
288
+ * @since 3.0
289
+ */
290
+ function id()
291
+ {
292
+ return isset( $this->attachments[$this->attachments_ref]->id ) ? $this->attachments[$this->attachments_ref]->id : null;
293
+ }
294
+
295
+
296
+
297
+ /**
298
+ * Returns the URL for the current Attachment
299
+ *
300
+ * @since 3.0
301
+ */
302
+ function url()
303
+ {
304
+ if( !isset( $this->attachments[$this->attachments_ref]->id ) )
305
+ return false;
306
+
307
+ return wp_get_attachment_url( $this->attachments[$this->attachments_ref]->id );
308
+ }
309
+
310
+
311
+
312
+ /**
313
+ * Returns the field value for the submitted field name
314
+ *
315
+ * @since 3.0
316
+ */
317
+ function field( $name = 'title' )
318
+ {
319
+ return isset( $this->attachments[$this->attachments_ref]->fields->$name ) ? $this->attachments[$this->attachments_ref]->fields->$name : false;
320
+ }
321
+
322
+
323
+
324
+ /**
325
+ * Fires all of our actions
326
+ *
327
+ * @since 3.0
328
+ */
329
+ function do_actions_filters()
330
+ {
331
+ // implement our default instance if appropriate
332
+ if( !defined( 'ATTACHMENTS_DEFAULT_INSTANCE' ) )
333
+ $this->register();
334
+
335
+ // facilitate user-defined instance registration
336
+ do_action( 'attachments_register', $this );
337
+ }
338
+
339
+
340
+
341
+ /**
342
+ * Enqueues our necessary assets
343
+ *
344
+ * @since 3.0
345
+ */
346
+ function assets( $hook )
347
+ {
348
+ global $post;
349
+
350
+ // we only want our assets on edit screens
351
+ if( !empty( $this->instances_for_post_type ) && 'edit.php' != $hook && 'post.php' != $hook && 'post-new.php' != $hook )
352
+ return;
353
+
354
+ // we only want to enqueue if appropriate
355
+ if( empty( $this->instances_for_post_type ) )
356
+ return;
357
+
358
+ $post_id = isset( $post->ID ) ? $post->ID : null;
359
+ wp_enqueue_media( array( 'post' => $post_id ) );
360
+
361
+ wp_enqueue_style( 'attachments', trailingslashit( $this->url ) . 'css/attachments.css', null, $this->version, 'screen' );
362
+
363
+ wp_enqueue_script( 'attachments', trailingslashit( $this->url ) . 'js/attachments.js', array( 'jquery', 'jquery-ui-sortable' ), $this->version, true );
364
+ }
365
+
366
+
367
+
368
+ /**
369
+ * Registers meta box(es) for the current edit screen
370
+ *
371
+ * @since 3.0
372
+ */
373
+ function meta_box_init()
374
+ {
375
+ $nonce_sent = false;
376
+
377
+ if( !empty( $this->instances_for_post_type ) )
378
+ {
379
+ foreach( $this->instances_for_post_type as $instance )
380
+ {
381
+ $instance_name = $instance;
382
+ $instance = (object) $this->instances[$instance];
383
+ $instance->name = $instance_name;
384
+
385
+ add_meta_box( 'attachments-' . $instance_name, __( esc_attr( $instance->label ) ), array( $this, 'meta_box_markup' ), $this->get_post_type(), 'normal', 'high', array( 'instance' => $instance, 'setup_nonce' => !$nonce_sent ) );
386
+
387
+ $nonce_sent = true;
388
+ }
389
+ }
390
+ }
391
+
392
+
393
+
394
+ /**
395
+ * Callback that outputs the meta box markup
396
+ *
397
+ * @since 3.0
398
+ */
399
+ function meta_box_markup( $post, $metabox )
400
+ {
401
+ // single out our $instance
402
+ $instance = (object) $metabox['args']['instance'];
403
+
404
+ if( $metabox['args']['setup_nonce'] )
405
+ wp_nonce_field( 'attachments_save', 'attachments_nonce' );
406
+
407
+ ?>
408
+
409
+ <div id="attachments-<?php echo $instance->name; ?>">
410
+ <?php if( !empty( $instance->note ) ) : ?>
411
+ <div class="attachments-note"><?php echo apply_filters( 'the_content', $instance->note ); ?></div>
412
+ <?php endif; ?>
413
+ <div class="attachments-container attachments-<?php echo $instance->name; ?>"><?php
414
+ if( isset( $instance->attachments ) && !empty( $instance->attachments ) )
415
+ {
416
+ foreach( $instance->attachments as $attachment )
417
+ {
418
+ // we need to give our Attachment a uid to carry through to all the fields
419
+ $attachment->uid = uniqid();
420
+
421
+ // we'll create the attachment
422
+ $this->create_attachment( $instance->name, $attachment );
423
+ }
424
+ }
425
+ ?></div>
426
+ <div class="attachments-invoke-wrapper">
427
+ <a class="button attachments-invoke"><?php _e( esc_attr( $instance->button_text ), 'attachments' ); ?></a>
428
+ </div>
429
+ </div>
430
+ <script type="text/javascript">
431
+ jQuery(document).ready(function($){
432
+ var $element = $('#attachments-<?php echo esc_attr( $instance->name ); ?>'),
433
+ title = '<?php echo __( esc_attr( $instance->label ) ); ?>',
434
+ button = '<?php echo __( esc_attr( $instance->modal_text ) ); ?>',
435
+ attachmentsframe;
436
+
437
+ $element.on( 'click', '.attachments-invoke', function( event ) {
438
+ var options, attachment;
439
+
440
+ event.preventDefault();
441
+
442
+ // if the frame already exists, open it
443
+ if ( attachmentsframe ) {
444
+ attachmentsframe.open();
445
+ return;
446
+ }
447
+
448
+ // set our seetings
449
+ attachmentsframe = wp.media({
450
+
451
+ title: title,
452
+
453
+ <?php if( $instance->limit < 0 || $instance->limit > 1 ) : ?>
454
+ multiple: true,
455
+ <?php endif; ?>
456
+
457
+ library: {
458
+ type: '<?php echo esc_attr( implode( ",", $instance->filetype ) ); ?>'
459
+ },
460
+
461
+ // Customize the submit button.
462
+ button: {
463
+ // Set the text of the button.
464
+ text: button
465
+ }
466
+ });
467
+
468
+ // set up our select handler
469
+ attachmentsframe.on( 'select', function() {
470
+
471
+ selection = attachmentsframe.state().get('selection');
472
+
473
+ if ( ! selection )
474
+ return;
475
+
476
+ // compile our Underscore template using Mustache syntax
477
+ _.templateSettings = {
478
+ variable : 'attachments',
479
+ interpolate : /\{\{(.+?)\}\}/g
480
+ }
481
+
482
+ var template = _.template($('script#tmpl-attachments-<?php echo $instance->name; ?>').html());
483
+
484
+ // loop through the selected files
485
+ selection.each( function( attachment ) {
486
+
487
+ // set our attributes to the template
488
+ attachment.attributes.attachment_uid = attachments_uniqid( 'attachmentsjs' );
489
+
490
+ // by default use the generic icon
491
+ attachment.attributes.attachment_thumb = attachment.attributes.icon;
492
+
493
+ // only thumbnails have sizes which is what we're on the hunt for
494
+ if(attachments_isset(attachment.attributes.sizes)){
495
+ if(attachments_isset(attachment.attributes.sizes.thumbnail)){
496
+ if(attachments_isset(attachment.attributes.sizes.thumbnail.url)){
497
+ // use the thumbnail
498
+ attachment.attributes.attachment_thumb = attachment.attributes.sizes.thumbnail.url;
499
+ }
500
+ }
501
+ }
502
+
503
+ var templateData = attachment.attributes;
504
+
505
+ // append the template
506
+ $element.find('.attachments-container').append(template(templateData));
507
+
508
+ // if it wasn't an image we need to ditch the dimensions
509
+ if(!attachments_isset(attachment.attributes.width)||!attachments_isset(attachment.attributes.height)){
510
+ $element.find('.attachments-attachment:last .dimensions').hide();
511
+ }
512
+ });
513
+ });
514
+
515
+ // open the frame
516
+ attachmentsframe.open();
517
+
518
+ });
519
+
520
+ $element.on( 'click', '.delete-attachment a', function( event ) {
521
+
522
+ var targetAttachment;
523
+
524
+ event.preventDefault();
525
+
526
+ targetAttachment = $(this).parents('.attachments-attachment');
527
+
528
+ targetAttachment.slideUp(function(){
529
+ targetAttachment.remove();
530
+ });
531
+
532
+ } );
533
+
534
+ });
535
+ </script>
536
+ <?php }
537
+
538
+
539
+
540
+ /**
541
+ * Support the inclusion of custom, user-defined field types
542
+ * Borrowed implementation from Custom Field Suite by Matt Gibbs
543
+ * https://uproot.us/docs/creating-custom-field-types/
544
+ *
545
+ * @since 3.0
546
+ **/
547
+ function get_field_types()
548
+ {
549
+ $field_types = array(
550
+ 'text' => ATTACHMENTS_DIR . 'classes/fields/class.field.text.php'
551
+ );
552
+
553
+ // support custom field types
554
+ // $field_types = apply_filters( 'attachments_fields', $field_types );
555
+
556
+ foreach( $field_types as $type => $path )
557
+ {
558
+ // store the registered classes so we can single out what gets added
559
+ $classes_before = get_declared_classes();
560
+
561
+ // proceed with inclusion
562
+ if( file_exists( $path ) )
563
+ {
564
+ // include the file
565
+ include_once( $path );
566
+
567
+ // determine it's class
568
+ $classes = get_declared_classes();
569
+ // the field's class is last in line
570
+ $field_class = end( $classes );
571
+
572
+ // create our link using our new field class
573
+ $field_types[$type] = $field_class;
574
+ }
575
+ }
576
+
577
+ // send it back
578
+ return $field_types;
579
+ }
580
+
581
+
582
+
583
+ /**
584
+ * Registers a field type for use within an instance
585
+ *
586
+ * @since 3.0
587
+ */
588
+ function register_field( $params = array() )
589
+ {
590
+ $defaults = array(
591
+ 'name' => 'title',
592
+ 'type' => 'text',
593
+ 'label' => __( 'Title', 'attachments' ),
594
+ );
595
+
596
+ $params = array_merge( $defaults, $params );
597
+
598
+ // ensure it's a valid type
599
+ if( !isset( $this->fields[$params['type']] ) )
600
+ return false;
601
+
602
+ // sanitize
603
+ if( isset( $params['name'] ) )
604
+ $params['name'] = str_replace( '-', '_', sanitize_title( $params['name'] ) );
605
+
606
+ if( isset( $params['label'] ) )
607
+ $params['label'] = __( esc_html( $params['label'] ) );
608
+
609
+ // instantiate the class for this field and send it back
610
+ return new $this->fields[ $params['type'] ]( $params['name'], $params['label'] );
611
+ }
612
+
613
+
614
+
615
+ /**
616
+ * Registers an Attachments instance
617
+ *
618
+ * @since 3.0
619
+ */
620
+ function register( $name = 'attachments', $params = array() )
621
+ {
622
+ $defaults = array(
623
+
624
+ // title of the meta box (string)
625
+ 'label' => __( 'Attachments', 'attachments' ),
626
+
627
+ // all post types to utilize (string|array)
628
+ 'post_type' => array( 'post', 'page' ),
629
+
630
+ // maximum number of Attachments (int) (-1 is unlimited)
631
+ 'limit' => -1,
632
+
633
+ // allowed file type(s) (array) (image|video|text|audio|application)
634
+ 'filetype' => null, // no filetype limit
635
+
636
+ // include a note within the meta box (string)
637
+ 'note' => null, // no note
638
+
639
+ // text for 'Attach' button (string)
640
+ 'button_text' => __( 'Attach', 'attachments' ),
641
+
642
+ // text for modal 'Attach' button (string)
643
+ 'modal_text' => __( 'Attach', 'attachments' ),
644
+
645
+ // fields for this instance (array)
646
+ 'fields' => array(
647
+ array(
648
+ 'name' => 'title', // unique field name
649
+ 'type' => 'text', // registered field type
650
+ 'label' => __( 'Title', 'attachments' ), // label to display
651
+ ),
652
+ array(
653
+ 'name' => 'caption', // unique field name
654
+ 'type' => 'text', // registered field type
655
+ 'label' => __( 'Caption', 'attachments' ), // label to display
656
+ ),
657
+ ),
658
+
659
+ );
660
+
661
+ $params = array_merge( $defaults, $params );
662
+
663
+ // sanitize
664
+ if( !is_array( $params['post_type'] ) )
665
+ $params['post_type'] = array( $params['post_type'] ); // we always want an array
666
+
667
+ if( !is_array( $params['filetype'] ) )
668
+ $params['filetype'] = array( $params['filetype'] ); // we always want an array
669
+
670
+ $params['label'] = esc_html( $params['label'] );
671
+ $params['limit'] = intval( $params['limit'] );
672
+ $params['note'] = esc_sql( $params['note'] );
673
+ $params['button_text'] = esc_attr( $params['button_text'] );
674
+ $params['modal_text'] = esc_attr( $params['modal_text'] );
675
+
676
+ // make sure we've got valid filetypes
677
+ if( is_array( $params['filetype'] ) )
678
+ {
679
+ foreach( $params['filetype'] as $key => $filetype )
680
+ {
681
+ if( !in_array( $filetype, $this->valid_filetypes ) )
682
+ {
683
+ unset( $params['filetype'][$key] );
684
+ }
685
+ }
686
+ }
687
+
688
+ // make sure the instance name is proper
689
+ $instance = str_replace( '-', '_', sanitize_title( $name ) );
690
+
691
+ // register the fields
692
+ if( isset( $params['fields'] ) && is_array( $params['fields'] ) && count( $params['fields'] ) )
693
+ {
694
+ foreach( $params['fields'] as $field )
695
+ {
696
+ // register the field
697
+ $this->register_field( $field );
698
+ }
699
+ }
700
+
701
+ // set the instance
702
+ $this->instances[$instance] = $params;
703
+
704
+ // set the Attachments for this instance
705
+ $this->instances[$instance]['attachments'] = $this->get_attachments( $instance );
706
+
707
+ }
708
+
709
+
710
+
711
+ /**
712
+ * Gets the applicable Attachments instances for the current post type
713
+ *
714
+ * @since 3.0
715
+ */
716
+ function get_instances_for_post_type( $post_type = null )
717
+ {
718
+ $post_type = ( !is_null( $post_type ) && post_type_exists( $post_type ) ) ? $post_type : $this->get_post_type();
719
+
720
+ $instances = array();
721
+
722
+ if( !empty( $this->instances ) )
723
+ {
724
+ foreach( $this->instances as $name => $params )
725
+ {
726
+ if( in_array( $post_type, $params['post_type'] ) )
727
+ {
728
+ $instances[] = $name;
729
+ }
730
+ }
731
+ }
732
+
733
+ return $instances;
734
+ }
735
+
736
+
737
+
738
+ /**
739
+ * Our own implementation of WordPress' get_post_type() as it's not
740
+ * functional when we need it
741
+ *
742
+ * @since 3.0
743
+ */
744
+ function get_post_type()
745
+ {
746
+ global $post;
747
+
748
+ // TODO: Retrieving the post_type at this point is ugly to say the least. This needs major cleanup.
749
+ if( empty( $post->ID ) && isset( $_GET['post_type'] ) )
750
+ {
751
+ $post_type = str_replace( '-', '_', sanitize_title( $_GET['post_type'] ) ); // TODO: Better sanitization
752
+ }
753
+ elseif( !empty( $post->ID ) )
754
+ {
755
+ $post_type = get_post_type( $post->ID );
756
+ }
757
+ elseif( isset( $_GET['post'] ) )
758
+ {
759
+ $post_type = get_post_type( intval( $_GET['post'] ) );
760
+ }
761
+ else
762
+ {
763
+ $post_type = 'post';
764
+ }
765
+
766
+ return $post_type;
767
+ }
768
+
769
+
770
+
771
+ /**
772
+ * Sets the applicable Attachments instances for the current post type
773
+ *
774
+ * @since 3.0
775
+ */
776
+ function set_instances_for_current_post_type()
777
+ {
778
+ // store the applicable instances for this post type
779
+ $this->instances_for_post_type = $this->get_instances_for_post_type( $this->get_post_type() );
780
+ }
781
+
782
+
783
+
784
+ /**
785
+ * Outputs HTML for a single Attachment within an instance
786
+ *
787
+ * @since 3.0
788
+ */
789
+ function create_attachment_field( $instance, $field, $attachment = null )
790
+ {
791
+
792
+ // the $field at this point is just the user-declared array
793
+ // we need to make it a field object
794
+ $type = $field['type'];
795
+
796
+ if( isset( $this->fields[$type] ) )
797
+ {
798
+ $name = sanitize_title( $field['name'] );
799
+ $label = esc_html( $field['label'] );
800
+
801
+ $value = ( isset( $attachment->fields->$name ) ) ? $attachment->fields->$name : null;
802
+
803
+ $field = new $this->fields[$type]( $name, $label, $value );
804
+ $field->Pvalue = $field->format_value_for_input( $field->value );
805
+
806
+ // does this field already have a unique ID?
807
+ $uid = ( isset( $attachment->uid ) ) ? $attachment->uid : null;
808
+
809
+ // TODO: make sure we've got a registered instance
810
+ $field->set_field_instance( $instance, $field );
811
+ $field->set_field_identifiers( $field, $uid );
812
+ $field->set_field_type( $type );
813
+
814
+ ?>
815
+ <div class="attachments-attachment-field attachments-attachment-field-<?php echo $instance; ?> attachments-attachment-field-<?php echo $field->type; ?> attachment-field-<?php echo $field->name; ?>">
816
+ <div class="attachment-label attachment-label-<?php echo $instance; ?>">
817
+ <label for="<?php echo $field->field_id; ?>"><?php echo $field->label; ?></label>
818
+ </div>
819
+ <div class="attachment-field attachment-field-<?php echo $instance; ?>">
820
+ <?php echo $this->create_field( $instance, $field ); ?>
821
+ </div>
822
+ </div>
823
+ <?php
824
+ }
825
+ else
826
+ {
827
+ $field = false;
828
+ }
829
+
830
+ return $field;
831
+ }
832
+
833
+
834
+
835
+ /**
836
+ * Outputs HTML for submitted field
837
+ *
838
+ * @since 3.0
839
+ */
840
+ function create_field( $instance, $field )
841
+ {
842
+ $field = (object) $field;
843
+
844
+ // with all of our attributes properly set, we can output
845
+ $field->html( $field );
846
+ }
847
+
848
+
849
+
850
+ /**
851
+ * Outputs all the necessary markup for an Attachment
852
+ *
853
+ * @since 3.0
854
+ */
855
+ function create_attachment( $instance, $attachment = null )
856
+ {
857
+ ?>
858
+ <div class="attachments-attachment attachments-attachment-<?php echo $instance; ?>">
859
+ <?php $array_flag = ( isset( $attachment->uid ) ) ? $attachment->uid : '{{ attachments.attachment_uid }}'; ?>
860
+
861
+ <input type="hidden" name="attachments[<?php echo $instance; ?>][<?php echo $array_flag; ?>][id]" value="<?php echo isset( $attachment->id ) ? $attachment->id : '{{ attachments.id }}' ; ?>" />
862
+
863
+ <?php
864
+ // since attributes can change over time (image gets replaced, cropped, etc.) we'll pull that info
865
+ if( isset( $attachment->id ) )
866
+ {
867
+ // we'll just use the full size since that's what Media in 3.5 uses
868
+ $attachment_meta = wp_get_attachment_metadata( $attachment->id );
869
+
870
+ // only images return the 'file' key
871
+ if( !isset( $attachment_meta['file'] ))
872
+ $attachment_meta['file'] = get_attached_file( $attachment->id );
873
+
874
+ $attachment->width = isset( $attachment_meta['width'] ) ? $attachment_meta['width'] : null;
875
+ $attachment->height = isset( $attachment_meta['height'] ) ? $attachment_meta['height'] : null;
876
+ $attachment->filename = end( explode( "/", $attachment_meta['file'] ) );
877
+
878
+ $attachment_mime = explode( '/', get_post_mime_type( $attachment->id ) );
879
+ $attachment->type = isset( $attachment_mime[0] ) ? $attachment_mime[0] : null;
880
+ $attachment->subtype = isset( $attachment_mime[1] ) ? $attachment_mime[1] : null;
881
+ }
882
+ ?>
883
+
884
+ <div class="attachment-meta media-sidebar">
885
+ <?php
886
+ $thumbnail = isset( $attachment->id ) ? wp_get_attachment_image_src( $attachment->id, 'thumbnail', true ) : false;
887
+
888
+ $image = $thumbnail ? $thumbnail[0] : '{{ attachments.attachment_thumb }}';
889
+ ?>
890
+ <div class="attachment-thumbnail">
891
+ <img src="<?php echo $image; ?>" alt="Thumbnail" />
892
+ </div>
893
+ <div class="attachment-details attachment-info details">
894
+ <div class="filename"><?php echo isset( $attachment->filename ) ? $attachment->filename : '{{ attachments.filename }}' ; ?></div>
895
+ <?php if( ( isset( $attachment->id ) && isset( $attachment->width ) ) || !isset( $attachment->id ) ) : ?>
896
+ <div class="dimensions"><?php echo isset( $attachment->width ) ? $attachment->width : '{{ attachments.width }}' ; ?> &times; <?php echo isset( $attachment->height ) ? $attachment->height : '{{ attachments.height }}' ; ?></div>
897
+ <?php endif; ?>
898
+ <div class="delete-attachment"><a href="#"><?php _e( 'Delete', 'attachments' ); ?></a></div>
899
+ </div>
900
+ </div>
901
+
902
+ <div class="attachments-handle"><img src="<?php echo trailingslashit( $this->url ) . 'images/handle.gif'; ?>" alt="Handle" width="20" height="20" /></div>
903
+
904
+ <div class="attachments-fields">
905
+ <?php
906
+ foreach( $this->instances[$instance]['fields'] as $field )
907
+ $field_ref = $this->create_attachment_field( $instance, $field, $attachment );
908
+ ?>
909
+ </div>
910
+
911
+ </div>
912
+ <?php
913
+ }
914
+
915
+
916
+
917
+ /**
918
+ * Outputs all necessary Backbone templates
919
+ * Each Backbone template includes each field present in an instance
920
+ *
921
+ * @since 3.0
922
+ */
923
+ function admin_footer()
924
+ {
925
+ if( !empty( $this->instances_for_post_type ) )
926
+ { ?>
927
+ <script type="text/javascript">
928
+ var ATTACHMENTS_VIEWS = {};
929
+ </script>
930
+ <?php
931
+ foreach( $this->instances_for_post_type as $instance ) : ?>
932
+ <script type="text/template" id="tmpl-attachments-<?php echo $instance; ?>">
933
+ <?php $this->create_attachment( $instance ); ?>
934
+ </script>
935
+ <?php endforeach;
936
+ }
937
+ }
938
+
939
+
940
+
941
+ /**
942
+ * Saves our Attachments metadata when the post is saved
943
+ *
944
+ * @since 3.0
945
+ */
946
+ function save( $post_id )
947
+ {
948
+ // is the user logged in?
949
+ if( !is_user_logged_in() )
950
+ return $post_id;
951
+
952
+ // is the nonce set?
953
+ if( !isset( $_POST['attachments_nonce'] ) )
954
+ return $post_id;
955
+
956
+ // is the nonce valid?
957
+ if( !wp_verify_nonce( $_POST['attachments_nonce'], 'attachments_save' ) )
958
+ return $post_id;
959
+
960
+ // can this user edit this post?
961
+ if( !current_user_can( 'edit_post', $post_id ) )
962
+ return $post_id;
963
+
964
+ // passed authentication, proceed with save
965
+
966
+ // if the user deleted all Attachments we won't have our key
967
+ $attachments_meta = isset( $_POST['attachments'] ) ? $_POST['attachments'] : array();
968
+
969
+ // final data store
970
+ $attachments = array();
971
+
972
+ // loop through each submitted instance
973
+ foreach( $attachments_meta as $instance => $instance_attachments )
974
+ {
975
+ // loop through each Attachment of this instance
976
+ foreach( $instance_attachments as $key => $attachment )
977
+ {
978
+ // since we're using JSON for storage in the database, we need
979
+ // to make sure that characters are encoded that would otherwise
980
+ // break the JSON
981
+ if( isset( $attachment['fields'] ) && is_array( $attachment['fields'] ) )
982
+ {
983
+
984
+ foreach( $attachment['fields'] as $key => $field_value )
985
+ {
986
+ // slashes were already added so we're going to strip them and encode ourselves
987
+ $attachment['fields'][$key] = htmlentities( stripslashes( $field_value ), ENT_QUOTES, 'UTF-8' );
988
+ }
989
+ }
990
+
991
+ $attachments[$instance][] = $attachment;
992
+ }
993
+ }
994
+
995
+ // we're going to store JSON
996
+ $attachments = json_encode( $attachments );
997
+
998
+ // we're going to wipe out any existing Attachments meta (because we'll put it back)
999
+ update_post_meta( $post_id, $this->meta_key, $attachments );
1000
+ }
1001
+
1002
+
1003
+
1004
+ /**
1005
+ * Retrieves all Attachments for the submitted instance and post ID
1006
+ *
1007
+ * @since 3.0
1008
+ */
1009
+ function get_attachments( $instance = '', $post_id = null )
1010
+ {
1011
+ global $post;
1012
+
1013
+ // if a post id was passed, we'll use it
1014
+ if( !is_null( $post_id ) )
1015
+ {
1016
+ $post_id = intval( $post_id );
1017
+ }
1018
+ elseif( is_null( $post_id ) && is_object( $post ) && isset( $post->ID ) )
1019
+ {
1020
+ $post_id = $post->ID;
1021
+ }
1022
+ elseif( isset( $_GET['post'] ) )
1023
+ {
1024
+ $post_id = intval( $_GET['post'] );
1025
+ }
1026
+ else
1027
+ {
1028
+ // no post ID, nothing to do...
1029
+ return;
1030
+ }
1031
+
1032
+ // grab our JSON and decode it
1033
+ $attachments_json = get_post_meta( $post_id, $this->meta_key, true );
1034
+ $attachments_raw = is_string( $attachments_json ) ? json_decode( $attachments_json ) : false;
1035
+
1036
+ // we need to decode the fields (that were encoded during save) and run them through
1037
+ // their format_value_for_input as defined in it's class
1038
+ if( isset( $attachments_raw->$instance ) )
1039
+ {
1040
+ foreach( $attachments_raw->$instance as $attachment )
1041
+ {
1042
+ if( is_object( $attachment->fields ) )
1043
+ {
1044
+ foreach( $attachment->fields as $key => $value )
1045
+ {
1046
+ // loop through the instance fields to get the type
1047
+ if( isset( $this->instances[$instance]['fields'] ) )
1048
+ {
1049
+ $type = '';
1050
+ foreach( $this->instances[$instance]['fields'] as $field )
1051
+ {
1052
+ if( isset( $field['name'] ) && $field['name'] == $key )
1053
+ {
1054
+ $type = isset( $field['type'] ) ? $field['type'] : false;
1055
+ break;
1056
+ }
1057
+ }
1058
+
1059
+ if( isset( $this->fields[$type] ) )
1060
+ {
1061
+ // we need to decode the html entities that were encoded for the save
1062
+ $attachment->fields->$key = html_entity_decode( $attachment->fields->$key, ENT_QUOTES, 'UTF-8' );
1063
+ }
1064
+ else
1065
+ {
1066
+ // the type doesn't exist
1067
+ $attachment->fields->$key = false;
1068
+ }
1069
+ }
1070
+ }
1071
+ }
1072
+ $attachments[] = $attachment;
1073
+ }
1074
+ }
1075
+ else
1076
+ {
1077
+ $attachments = false;
1078
+ }
1079
+
1080
+ return $attachments;
1081
+ }
1082
+
1083
+
1084
+
1085
+ /**
1086
+ * Determines whether or not there is 'active' legacy data the user may not know about
1087
+ *
1088
+ * @since 3.0
1089
+ */
1090
+ function has_outstanding_legacy_data()
1091
+ {
1092
+ if(
1093
+ // migration has not taken place and we have legacy data
1094
+ ( false == get_option( 'attachments_migrated' ) && !empty( $this->legacy ) )
1095
+
1096
+ &&
1097
+
1098
+ // we're not intentionally ignoring the message
1099
+ ( false == get_option( 'attachments_ignore_migration' ) )
1100
+ )
1101
+ {
1102
+ return true;
1103
+ }
1104
+ else
1105
+ {
1106
+ return false;
1107
+ }
1108
+ }
1109
+
1110
+
1111
+
1112
+ /**
1113
+ * Outputs a WordPress message to notify user of legacy data
1114
+ *
1115
+ * @since 3.0
1116
+ */
1117
+ function admin_notice()
1118
+ {
1119
+
1120
+ if( $this->has_outstanding_legacy_data() && ( isset( $_GET['page'] ) && $_GET['page'] !== 'attachments' || !isset( $_GET['page'] ) ) ) : ?>
1121
+ <div class="message updated" id="message">
1122
+ <p><?php _e( '<strong>Attachments has detected legacy Attachments data.</strong> A lot has changed since Attachments 1.x.' ,'attachments' ); ?> <a href="options-general.php?page=attachments&amp;overview=1"><?php _e( 'Find out more', 'attachments' ); ?>.</a></p>
1123
+ </div>
1124
+ <?php endif;
1125
+ }
1126
+
1127
+
1128
+
1129
+ /**
1130
+ * Implements our WordPress pointer if necessary
1131
+ *
1132
+ * @since 3.0
1133
+ */
1134
+ function admin_pointer( $hook_suffix )
1135
+ {
1136
+
1137
+ // Assume pointer shouldn't be shown
1138
+ $enqueue_pointer_script_style = false;
1139
+
1140
+ // Get array list of dismissed pointers for current user and convert it to array
1141
+ $dismissed_pointers = explode( ',', get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
1142
+
1143
+ // Check if our pointer is not among dismissed ones
1144
+ if( $this->legacy && !in_array( 'attachments_legacy', $dismissed_pointers ) ) {
1145
+ $enqueue_pointer_script_style = true;
1146
+
1147
+ // Add footer scripts using callback function
1148
+ add_action( 'admin_print_footer_scripts', array( $this, 'pointer_legacy' ) );
1149
+ }
1150
+
1151
+ // Enqueue pointer CSS and JS files, if needed
1152
+ if( $enqueue_pointer_script_style ) {
1153
+ wp_enqueue_style( 'wp-pointer' );
1154
+ wp_enqueue_script( 'wp-pointer' );
1155
+ }
1156
+ }
1157
+
1158
+
1159
+
1160
+ /**
1161
+ * Pointer that calls attention to legacy data
1162
+ *
1163
+ * @since 3.0
1164
+ */
1165
+ function pointer_legacy()
1166
+ {
1167
+ $pointer_content = "<h3>". __( esc_html( 'Attachments 3.0 brings big changes!' ), 'attachments' ) ."</h3>";
1168
+ $pointer_content .= "<p>". __( esc_html( 'It is very important that you take a few minutes to see what has been updated. The changes will affect your themes/plugins.' ), 'attachments' ) ."</p>";
1169
+ ?>
1170
+
1171
+ <script type="text/javascript">
1172
+ jQuery(document).ready( function($) {
1173
+ $('#message a').pointer({
1174
+ content:'<?php echo $pointer_content; ?>',
1175
+ position:{
1176
+ edge:'top',
1177
+ align:'center'
1178
+ },
1179
+ pointerWidth:350,
1180
+ close:function() {
1181
+ $.post( ajaxurl, {
1182
+ pointer: 'attachments_legacy',
1183
+ action: 'dismiss-wp-pointer'
1184
+ });
1185
+ }
1186
+ }).pointer('open');
1187
+ });
1188
+ </script>
1189
+ <?php
1190
+ }
1191
+
1192
+
1193
+
1194
+ /**
1195
+ * Callback to implement our Settings page
1196
+ *
1197
+ * @since 3.0
1198
+ */
1199
+ function admin_page()
1200
+ {
1201
+ add_options_page( 'Settings', __( 'Attachments', 'attachments' ), 'manage_options', 'attachments', array( $this, 'options_page' ) );
1202
+ }
1203
+
1204
+
1205
+
1206
+ /**
1207
+ * Callback to output our Settings page markup
1208
+ *
1209
+ * @since 3.0
1210
+ */
1211
+ function options_page()
1212
+ {
1213
+ include_once( ATTACHMENTS_DIR . '/views/options.php' );
1214
+ }
1215
+
1216
+ }
1217
+
1218
+ endif; // class_exists check
1219
+
1220
+ new Attachments();
classes/class.field.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Attachments Field Base Class
5
+ *
6
+ * @package Attachments
7
+ * @subpackage Main
8
+ */
9
+
10
+ // Declare our class
11
+ if ( !class_exists( 'Attachments_Field' ) ) :
12
+
13
+ interface Attachments_Field_Template
14
+ {
15
+ public function html( $field );
16
+ public function format_value_for_input( $value, $field = null );
17
+ public function input_head();
18
+ }
19
+
20
+ class Attachments_Field implements Attachments_Field_Template
21
+ {
22
+ public $instance; // the instance this field is used within
23
+ public $name; // the user-defined field name
24
+ public $field_name; // the name attribute to be used
25
+ public $field_id; // the id attribute to be used
26
+ public $label; // the field label
27
+ public $type; // field type as it was registered
28
+ public $uid; // unique id for field
29
+ public $value; // the value for the field
30
+
31
+ function __construct( $name = 'name', $label = 'Name', $value = null )
32
+ {
33
+ $this->name = sanitize_title( $name );
34
+ $this->label = __( esc_attr( $label) );
35
+ $this->value = $value;
36
+ }
37
+
38
+ function set_field_instance( $instance, $field )
39
+ {
40
+ $field->instance = $instance;
41
+ }
42
+
43
+ function set_field_identifiers( $field, $uid = null )
44
+ {
45
+ // we MUST have an instance
46
+ if( empty( $field->instance ) )
47
+ return false;
48
+
49
+ // if we're pulling an existing Attachment (field has a value) we're going to use
50
+ // a PHP uniqid to set up our array flags but if we're setting up our Underscore
51
+ // template we need to use a variable flag to be processed later
52
+ $this->uid = !is_null( $uid ) ? $uid : '{{ attachments.attachment_uid }}';
53
+
54
+ // set the name
55
+ $field->field_name = "attachments[$field->instance][$this->uid][fields][$field->name]";
56
+
57
+ // set the id
58
+ $field->field_id = $this->field_name . $this->uid;
59
+ }
60
+
61
+ function set_field_type( $field_type )
62
+ {
63
+ $this->type = $field_type;
64
+ }
65
+
66
+ public function html( $field )
67
+ {
68
+ ?>
69
+ <input type="text" name="<?php esc_attr_e( $field->field_name ); ?>" id="<?php esc_attr_e( $field->field_id ); ?>" class="attachments attachments-field attachments-field-<?php esc_attr_e( $field->field_name ); ?> attachments-field-<?php esc_attr_e( $field->field_id ); ?>" value="<?php esc_attr_e( $field->value ); ?>" />
70
+ <?php
71
+ }
72
+
73
+ public function format_value_for_input( $value, $field = null )
74
+ {
75
+ return $value;
76
+ }
77
+
78
+ public function input_head()
79
+ {
80
+ return;
81
+ }
82
+
83
+ }
84
+
85
+ endif; // class_exists check
classes/fields/class.field.text.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Attachments text field
5
+ *
6
+ * @package Attachments
7
+ * @subpackage Main
8
+ */
9
+
10
+ class Attachments_Field_Text extends Attachments_Field implements Attachments_Field_Template
11
+ {
12
+
13
+ function __construct( $name = 'name', $label = 'Name', $value = null )
14
+ {
15
+ parent::__construct( $name, $label, $value );
16
+ }
17
+
18
+ function html( $field )
19
+ {
20
+ ?>
21
+ <input type="text" name="<?php esc_attr_e( $field->field_name ); ?>" id="<?php esc_attr_e( $field->field_id ); ?>" class="attachments attachments-field attachments-field-<?php esc_attr_e( $field->field_name ); ?> attachments-field-<?php esc_attr_e( $field->field_id ); ?>" value="<?php esc_attr_e( $field->value ); ?>" />
22
+ <?php
23
+ }
24
+
25
+ function format_value_for_input( $value, $field = null )
26
+ {
27
+ return htmlspecialchars( $value, ENT_QUOTES );
28
+ }
29
+
30
+ public function input_head()
31
+ {
32
+ return;
33
+ }
34
+
35
+ }
classes/fields/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php
classes/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php
css/attachments.css CHANGED
@@ -1,73 +1,166 @@
1
- /* ============ */
2
- /* = META BOX = */
3
- /* ============ */
4
-
5
- #attachments-inner { padding-top:3px; }
6
- ul#attachments-actions { overflow:hidden; zoom:1; padding-top:4px; }
7
- ul#attachments-actions li { width:50%; float:left; }
8
- li#attachments-add-new { float:right; text-align:right; }
9
-
10
- #attachments-instructions { margin:0; padding:12px 0 !important; }
11
-
12
- #attachments-file-list { padding:0; }
13
- .attachments-file-section { padding:0 0 20px 0; }
14
- p.attachments-actions { float:right; margin:6px 0 0 !important; }
15
-
16
- #attachments-file-details .attachments img { display:block; }
17
- #attachments-file-details .attachments a { display:block; border:3px solid #fff; float:left; }
18
- #attachments-file-details .attachments a:hover { border:3px solid #ccc; }
19
-
20
- #attachments-file-details .attachments a.attachments-selected { border:3px solid #eb3525; }
21
- span.attachments-attached { background:#fff; color:#d54e21; padding-left:10px; font-style:italic; }
22
-
23
- /* File listings, not images */
24
- #attachments-file-details .attachments-alt li { width:290px; }
25
- #attachments-file-details .attachments-alt span.attachments-thumbnail { display:block; width:70px; float:left; }
26
- #attachments-file-details .attachments-alt h2.attachments-title-display { display:block; width:220px; float:left; text-decoration:none; font:20px Georgia,"Times New Roman","Bitstream Charter",Times,serif; font-style:italic; font-weight:normal; height:2.4em; overflow:hidden; }
27
-
28
- #attachments-file-details .attachments-alt li a { display:block; border:0; text-decoration:none; }
29
- #attachments-file-details .attachments-alt li a.attachments-selected { border:0; }
30
- #attachments-file-details .attachments-alt li a span.attachments-thumbnail img { border:3px solid #fff; }
31
- #attachments-file-details .attachments-alt li a.attachments-selected span.attachments-thumbnail img { border:3px solid #eb3525; }
32
-
33
-
34
- /* ========================= */
35
- /* = META BOX FILE LISTING = */
36
- /* ========================= */
37
- #attachments-list ul { padding:10px 0; }
38
- #attachments-list li.attachments-file { overflow:hidden; zoom:1; }
39
- .attachments-data { display:none; }
40
- #poststuff li.attachments-file { height:115px; }
41
- #poststuff li.attachments-file h2 { margin:0; overflow:hidden; zoom:1; }
42
- #poststuff li.attachments-file h2 a { text-decoration:none; color:inherit; }
43
- #poststuff li.attachments-file h2 span { display:block; float:left; }
44
- #poststuff li.attachments-file h2 a span.attachment-handle-icon { padding:6px 0 0 0; cursor:move; }
45
- #poststuff li.attachments-file h2 span.attachment-name { padding:0 10px; height:2em; overflow:hidden; width:60%; }
46
- #poststuff li.attachments-file h2 span.attachment-delete { width:80px; text-align:center; padding:0.7em 0 0 0; float:right; margin-right:3px; }
47
- #poststuff li.attachments-file h2 span.attachment-delete a { font:11px "Lucida Grande",Verdana,Arial,"Bitstream Vera Sans",sans-serif; color:#21759b; text-decoration:underline; }
48
- #poststuff li.attachments-file h2 span.attachment-delete a:hover { color:#d54e21; }
49
-
50
- #attachments-list .attachments-file { overflow:hidden; zoom:1; }
51
- #attachments-list .attachments-fields { width:80%; float:left; }
52
- #attachments-list .attachment-thumbnail { width:80px; float:right; margin-right:3px; }
53
- #attachments-list .attachments-thumbnail { width:80px; float:right; text-align:right; }
54
- #attachments-list .attachments-thumbnail img { display:block; max-width:80px; margin:0 auto; }
55
-
56
- .attachments-fields .textfield { overflow:hidden; zoom:1; padding-bottom:10px; }
57
- .attachments-fields .textfield label { display:block; width:20%; float:left; padding-top:6px; }
58
- .attachments-fields .textfield input { display:block; width:75%; float:left; }
59
-
60
-
61
- /* =========== */
62
- /* = OPTIONS = */
63
- /* =========== */
64
- .attachments_checkbox { overflow:hidden; zoom:1; padding:0 0 7px 0; }
65
- .attachments_checkbox input { display:block; float:left; margin-top:2px; }
66
- .attachments_checkbox label { display:block; float:left; padding:0 0 0 7px; }
67
- .attachments_checkbox p.note { clear:both; font-style:italic; padding:4px 0 0 21px; max-width:550px; color:#888; }
68
-
69
- #attachments-tabs .subsubsub { float:left; }
70
- #attachments-tabs .subsubsub a { color:#21759b !important; }
71
- #attachments-tabs-wrapper { border-bottom:1px solid #dfdfdf; position:relative; }
72
- #attachments-tabs #sidemenu { overflow:hidden; zoom:1; background:#f9f9f9; float:none !important; margin:0; }
73
- #attachments-live-filter { display:block; width:140px; float:left; margin:0 0 10px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ a.attachments-invoke {
2
+ margin-top:5px;
3
+ margin-bottom:4px;
4
+ }
5
+
6
+ .attachments-attachment {
7
+ position:relative;
8
+ overflow:hidden;
9
+ zoom:1;
10
+ padding:5px 0 25px;
11
+ border-bottom:1px solid #e7e7e7;
12
+ }
13
+
14
+ .attachments-attachment:first-of-type {
15
+ padding-top:0;
16
+ }
17
+
18
+ .attachments-attachment:last-of-type {
19
+ border-bottom:0;
20
+ margin-bottom:30px;
21
+ padding-bottom:0;
22
+ }
23
+
24
+ .attachments-note {
25
+ padding-bottom:8px;
26
+ }
27
+
28
+ .attachments-note:not(:empty) + .attachments-container > .attachments-attachment:first-of-type {
29
+ margin-top:-20px;
30
+ }
31
+
32
+ .attachments-container {
33
+ padding-bottom:34px;
34
+ }
35
+
36
+ .attachments-invoke-wrapper {
37
+ position:absolute;
38
+ bottom:0;
39
+ left:0;
40
+ width:100%;
41
+ height:36px;
42
+ padding-top:12px;
43
+ background:#fcfcfc;
44
+ margin-bottom:-8px;
45
+ border-bottom-left-radius:3px;
46
+ border-bottom-right-radius:3px;
47
+ text-align:center;
48
+ border-top:1px solid #dfdfdf;
49
+ }
50
+
51
+ .attachments-container .ui-sortable-helper {
52
+ background:#F9F9F9;
53
+ }
54
+
55
+ .attachments-attachment-highlight {
56
+ min-height:125px;
57
+ background:#f1f1f1;
58
+ border:1px solid #cecece;
59
+ border-radius:2px;
60
+ }
61
+
62
+ .attachments-attachment .attachment-meta {
63
+ /* Reset some WP defaults */
64
+ bottom:auto;
65
+ border:0;
66
+
67
+ /* Our styles */
68
+ position:absolute;
69
+ right:0;
70
+ top:0;
71
+ margin-top:36px;
72
+ width:225px;
73
+ overflow:hidden;
74
+ zoom:1;
75
+ padding:5px;
76
+ background:#fdfdfd;
77
+ border:1px solid #DFDFDF;
78
+ border:1px solid rgba(223,223,223,0.8);
79
+ border-radius:2px;
80
+ }
81
+
82
+ .attachments-attachment:first-of-type .attachment-meta {
83
+ margin-top:32px;
84
+ }
85
+
86
+ .attachments-attachment .attachment-meta .attachment-info {
87
+ /* Reset some WP defaults */
88
+ min-height:1px;
89
+ margin-bottom:0;
90
+ border-bottom:0;
91
+ box-shadow:none;
92
+ padding-bottom:0;
93
+ }
94
+
95
+ .attachments-attachment .attachment-meta .attachment-details {
96
+ width:135px;
97
+ float:right;
98
+ margin:0;
99
+ padding:0;
100
+ }
101
+
102
+ .attachments-attachment .attachment-meta .attachment-info .filename {
103
+ white-space:nowrap;
104
+ width:100%;
105
+ overflow:hidden;
106
+ text-overflow:ellipsis;
107
+ }
108
+
109
+ .attachments-attachment .attachment-meta .attachment-thumbnail {
110
+ width:80px;
111
+ float:left;
112
+ }
113
+
114
+ .attachments-attachment .attachment-meta .attachment-thumbnail img {
115
+ display:block;
116
+ max-width:100%;
117
+ height:auto !important;
118
+ max-height:80px;
119
+ border-radius:2px;
120
+ margin:0 auto;
121
+ }
122
+
123
+ .attachments-attachment .attachment-meta .attachment-actions {
124
+ width:130px;
125
+ float:right;
126
+ }
127
+
128
+ .attachments-fields {
129
+ margin-right:250px;
130
+ margin-left:40px;
131
+ padding-top:10px;
132
+ }
133
+
134
+ .attachments-fields .attachments-attachment-field {
135
+ overflow:hidden;
136
+ zoom:1;
137
+ padding:8px 0;
138
+ }
139
+
140
+ .attachments-fields label {
141
+ display:block;
142
+ margin-bottom:3px;
143
+ }
144
+
145
+
146
+ /* Text field styling */
147
+ .attachments-attachment-field-text input {
148
+ display:block;
149
+ width:100%;
150
+ }
151
+
152
+ .attachments-handle {
153
+ position:absolute;
154
+ left:0;
155
+ top:20px;
156
+ opacity:0.5;
157
+ }
158
+
159
+ .attachments-attachment:first-of-type .attachments-handle {
160
+ top:17px;
161
+ }
162
+
163
+ .attachments-handle img {
164
+ display:block;
165
+ cursor:pointer;
166
+ }
css/index.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Do not modify the files in this folder.
5
+ */
attachments.options.php → deprecated/attachments.options.php RENAMED
File without changes
attachments.php → deprecated/attachments.php RENAMED
@@ -1,11 +1,6 @@
1
  <?php
2
  /*
3
- Plugin Name: Attachments
4
- Plugin URI: http://mondaybynoon.com/wordpress-attachments/
5
- Description: Attachments gives the ability to append any number of Media Library items to Pages, Posts, and Custom Post Types
6
- Version: 1.6.2.1
7
- Author: Jonathan Christopher
8
- Author URI: http://mondaybynoon.com/
9
  */
10
 
11
  /* Copyright 2009-2012 Jonathan Christopher (email : jonathan@irontoiron.com)
@@ -25,6 +20,9 @@
25
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26
  */
27
 
 
 
 
28
 
29
  // constant definition
30
  if( !defined( 'IS_ADMIN' ) )
@@ -59,6 +57,9 @@ if( !version_compare( PHP_VERSION, '5.2', '>=' ) || !version_compare( $wp_versio
59
  }
60
 
61
 
 
 
 
62
 
63
  // =========
64
  // = HOOKS =
@@ -265,34 +266,6 @@ function attachments_edit_post_types()
265
  <?php }
266
 
267
 
268
- /**
269
- * Compares two array values with the same key "order"
270
- *
271
- * @param string $a First value
272
- * @param string $b Second value
273
- * @return int
274
- * @author Jonathan Christopher
275
- */
276
- function attachments_cmp($a, $b)
277
- {
278
- $a = intval( $a['order'] );
279
- $b = intval( $b['order'] );
280
-
281
- if( $a < $b )
282
- {
283
- return -1;
284
- }
285
- else if( $a > $b )
286
- {
287
- return 1;
288
- }
289
- else
290
- {
291
- return 0;
292
- }
293
- }
294
-
295
-
296
  /**
297
  * Creates the markup for the WordPress admin options page
298
  *
@@ -382,7 +355,7 @@ function attachments_attachment_markup( $name = null, $title = null, $caption =
382
  <li class="attachments-file">
383
  <h2>
384
  <a href="#" class="attachment-handle">
385
- <span class="attachment-handle-icon"><img src="<?php echo WP_PLUGIN_URL; ?>/attachments/images/handle.gif" alt="Drag" /></span>
386
  </a>
387
  <span class="attachment-name"><?php echo empty( $name ) ? '{{name}}' : $name; ?></span>
388
  <span class="attachment-delete"><a href="#"><?php _e("Delete", "attachments")?></a></span>
@@ -575,78 +548,4 @@ function attachments_save($post_id)
575
 
576
  }
577
 
578
- }
579
-
580
-
581
- /**
582
- * Returns a formatted filesize
583
- *
584
- * @param string $path Path to file on disk
585
- * @return string $formatted formatted filesize
586
- * @author Jonathan Christopher
587
- */
588
- function attachments_get_filesize_formatted( $path = NULL )
589
- {
590
- $formatted = '0 bytes';
591
- if( file_exists( $path ) )
592
- {
593
- $formatted = size_format( @filesize( $path ) );
594
- }
595
- return $formatted;
596
- }
597
-
598
-
599
- /**
600
- * Retrieves all Attachments for provided Post or Page
601
- *
602
- * @param int $post_id (optional) ID of target Post or Page, otherwise pulls from global $post
603
- * @return array $post_attachments
604
- * @author Jonathan Christopher
605
- * @author JR Tashjian
606
- */
607
-
608
- function attachments_get_attachments( $post_id=null )
609
- {
610
- global $post;
611
-
612
- if( $post_id==null )
613
- {
614
- $post_id = $post->ID;
615
- }
616
-
617
- // get all attachments
618
- $existing_attachments = get_post_meta( $post_id, '_attachments', false );
619
-
620
- // We can now proceed as normal, all legacy data should now be upgraded
621
-
622
- $post_attachments = array();
623
-
624
- if( is_array( $existing_attachments ) && count( $existing_attachments ) > 0 )
625
- {
626
-
627
- foreach ($existing_attachments as $attachment)
628
- {
629
- // decode and unserialize the data
630
- $data = unserialize( base64_decode( $attachment ) );
631
-
632
- array_push( $post_attachments, array(
633
- 'id' => stripslashes( $data['id'] ),
634
- 'name' => stripslashes( get_the_title( $data['id'] ) ),
635
- 'mime' => stripslashes( get_post_mime_type( $data['id'] ) ),
636
- 'title' => stripslashes( $data['title'] ),
637
- 'caption' => stripslashes( $data['caption'] ),
638
- 'filesize' => stripslashes( attachments_get_filesize_formatted( get_attached_file( $data['id'] ) ) ),
639
- 'location' => stripslashes( wp_get_attachment_url( $data['id'] ) ),
640
- 'order' => stripslashes( $data['order'] )
641
- ));
642
- }
643
-
644
- // sort attachments
645
- if( count( $post_attachments ) > 1 )
646
- {
647
- usort( $post_attachments, "attachments_cmp" );
648
- }
649
- }
650
-
651
- return $post_attachments;
652
  }
1
  <?php
2
  /*
3
+ THIS IS A LEGACY VERSION OF ATTACHMENTS AND IS CONSIDERED DEPRECATED
 
 
 
 
 
4
  */
5
 
6
  /* Copyright 2009-2012 Jonathan Christopher (email : jonathan@irontoiron.com)
20
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
  */
22
 
23
+ // Exit if accessed directly
24
+ if( !defined( 'ABSPATH' ) ) exit;
25
+
26
 
27
  // constant definition
28
  if( !defined( 'IS_ADMIN' ) )
57
  }
58
 
59
 
60
+ // we moved all attachments_get_attachments() functions to an external file in version 3.0
61
+ include_once 'get-attachments.php';
62
+
63
 
64
  // =========
65
  // = HOOKS =
266
  <?php }
267
 
268
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
  /**
270
  * Creates the markup for the WordPress admin options page
271
  *
355
  <li class="attachments-file">
356
  <h2>
357
  <a href="#" class="attachment-handle">
358
+ <span class="attachment-handle-icon"><img src="<?php echo WP_PLUGIN_URL; ?>/attachments/deprecated/images/handle.gif" alt="Drag" /></span>
359
  </a>
360
  <span class="attachment-name"><?php echo empty( $name ) ? '{{name}}' : $name; ?></span>
361
  <span class="attachment-delete"><a href="#"><?php _e("Delete", "attachments")?></a></span>
548
 
549
  }
550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
551
  }
deprecated/css/attachments.css ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* ============ */
2
+ /* = META BOX = */
3
+ /* ============ */
4
+
5
+ #attachments-inner { padding-top:3px; }
6
+ ul#attachments-actions { overflow:hidden; zoom:1; padding-top:4px; }
7
+ ul#attachments-actions li { width:50%; float:left; }
8
+ li#attachments-add-new { float:right; text-align:right; }
9
+
10
+ #attachments-instructions { margin:0; padding:12px 0 !important; }
11
+
12
+ #attachments-file-list { padding:0; }
13
+ .attachments-file-section { padding:0 0 20px 0; }
14
+ p.attachments-actions { float:right; margin:6px 0 0 !important; }
15
+
16
+ #attachments-file-details .attachments img { display:block; }
17
+ #attachments-file-details .attachments a { display:block; border:3px solid #fff; float:left; }
18
+ #attachments-file-details .attachments a:hover { border:3px solid #ccc; }
19
+
20
+ #attachments-file-details .attachments a.attachments-selected { border:3px solid #eb3525; }
21
+ span.attachments-attached { background:#fff; color:#d54e21; padding-left:10px; font-style:italic; }
22
+
23
+ /* File listings, not images */
24
+ #attachments-file-details .attachments-alt li { width:290px; }
25
+ #attachments-file-details .attachments-alt span.attachments-thumbnail { display:block; width:70px; float:left; }
26
+ #attachments-file-details .attachments-alt h2.attachments-title-display { display:block; width:220px; float:left; text-decoration:none; font:20px Georgia,"Times New Roman","Bitstream Charter",Times,serif; font-style:italic; font-weight:normal; height:2.4em; overflow:hidden; }
27
+
28
+ #attachments-file-details .attachments-alt li a { display:block; border:0; text-decoration:none; }
29
+ #attachments-file-details .attachments-alt li a.attachments-selected { border:0; }
30
+ #attachments-file-details .attachments-alt li a span.attachments-thumbnail img { border:3px solid #fff; }
31
+ #attachments-file-details .attachments-alt li a.attachments-selected span.attachments-thumbnail img { border:3px solid #eb3525; }
32
+
33
+
34
+ /* ========================= */
35
+ /* = META BOX FILE LISTING = */
36
+ /* ========================= */
37
+ #attachments-list ul { padding:10px 0; }
38
+ #attachments-list li.attachments-file { overflow:hidden; zoom:1; }
39
+ .attachments-data { display:none; }
40
+ #poststuff li.attachments-file { height:115px; }
41
+ #poststuff li.attachments-file h2 { margin:0; overflow:hidden; zoom:1; }
42
+ #poststuff li.attachments-file h2 a { text-decoration:none; color:inherit; }
43
+ #poststuff li.attachments-file h2 span { display:block; float:left; }
44
+ #poststuff li.attachments-file h2 a span.attachment-handle-icon { padding:6px 0 0 0; cursor:move; }
45
+ #poststuff li.attachments-file h2 span.attachment-name { padding:0 10px; height:2em; overflow:hidden; width:60%; }
46
+ #poststuff li.attachments-file h2 span.attachment-delete { width:80px; text-align:center; padding:0.7em 0 0 0; float:right; margin-right:3px; }
47
+ #poststuff li.attachments-file h2 span.attachment-delete a { font:11px "Lucida Grande",Verdana,Arial,"Bitstream Vera Sans",sans-serif; color:#21759b; text-decoration:underline; }
48
+ #poststuff li.attachments-file h2 span.attachment-delete a:hover { color:#d54e21; }
49
+
50
+ #attachments-list .attachments-file { overflow:hidden; zoom:1; }
51
+ #attachments-list .attachments-fields { width:80%; float:left; }
52
+ #attachments-list .attachment-thumbnail { width:80px; float:right; margin-right:3px; }
53
+ #attachments-list .attachments-thumbnail { width:80px; float:right; text-align:right; }
54
+ #attachments-list .attachments-thumbnail img { display:block; max-width:80px; margin:0 auto; }
55
+
56
+ .attachments-fields .textfield { overflow:hidden; zoom:1; padding-bottom:10px; }
57
+ .attachments-fields .textfield label { display:block; width:20%; float:left; padding-top:6px; }
58
+ .attachments-fields .textfield input { display:block; width:75%; float:left; }
59
+
60
+
61
+ /* =========== */
62
+ /* = OPTIONS = */
63
+ /* =========== */
64
+ .attachments_checkbox { overflow:hidden; zoom:1; padding:0 0 7px 0; }
65
+ .attachments_checkbox input { display:block; float:left; margin-top:2px; }
66
+ .attachments_checkbox label { display:block; float:left; padding:0 0 0 7px; }
67
+ .attachments_checkbox p.note { clear:both; font-style:italic; padding:4px 0 0 21px; max-width:550px; color:#888; }
68
+
69
+ #attachments-tabs .subsubsub { float:left; }
70
+ #attachments-tabs .subsubsub a { color:#21759b !important; }
71
+ #attachments-tabs-wrapper { border-bottom:1px solid #dfdfdf; position:relative; }
72
+ #attachments-tabs #sidemenu { overflow:hidden; zoom:1; background:#f9f9f9; float:none !important; margin:0; }
73
+ #attachments-live-filter { display:block; width:140px; float:left; margin:0 0 10px; }
deprecated/css/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php
deprecated/get-attachments.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Exit if accessed directly
4
+ if( !defined( 'ABSPATH' ) ) exit;
5
+
6
+ /**
7
+ * Compares two array values with the same key "order"
8
+ *
9
+ * @param string $a First value
10
+ * @param string $b Second value
11
+ * @return int
12
+ * @author Jonathan Christopher
13
+ */
14
+ function attachments_cmp($a, $b)
15
+ {
16
+ $a = intval( $a['order'] );
17
+ $b = intval( $b['order'] );
18
+
19
+ if( $a < $b )
20
+ {
21
+ return -1;
22
+ }
23
+ else if( $a > $b )
24
+ {
25
+ return 1;
26
+ }
27
+ else
28
+ {
29
+ return 0;
30
+ }
31
+ }
32
+
33
+
34
+ /**
35
+ * Returns a formatted filesize
36
+ *
37
+ * @param string $path Path to file on disk
38
+ * @return string $formatted formatted filesize
39
+ * @author Jonathan Christopher
40
+ */
41
+ function attachments_get_filesize_formatted( $path = NULL )
42
+ {
43
+ $formatted = '0 bytes';
44
+ if( file_exists( $path ) )
45
+ {
46
+ $formatted = size_format( @filesize( $path ) );
47
+ }
48
+ return $formatted;
49
+ }
50
+
51
+
52
+ /**
53
+ * Retrieves all Attachments for provided Post or Page
54
+ *
55
+ * @param int $post_id (optional) ID of target Post or Page, otherwise pulls from global $post
56
+ * @return array $post_attachments
57
+ * @author Jonathan Christopher
58
+ * @author JR Tashjian
59
+ */
60
+
61
+ function attachments_get_attachments( $post_id=null )
62
+ {
63
+ global $post;
64
+
65
+ if( $post_id==null )
66
+ {
67
+ $post_id = $post->ID;
68
+ }
69
+
70
+ // get all attachments
71
+ $existing_attachments = get_post_meta( $post_id, '_attachments', false );
72
+
73
+ // We can now proceed as normal, all legacy data should now be upgraded
74
+
75
+ $post_attachments = array();
76
+
77
+ if( is_array( $existing_attachments ) && count( $existing_attachments ) > 0 )
78
+ {
79
+
80
+ foreach ($existing_attachments as $attachment)
81
+ {
82
+ // decode and unserialize the data
83
+ $data = unserialize( base64_decode( $attachment ) );
84
+
85
+ array_push( $post_attachments, array(
86
+ 'id' => stripslashes( $data['id'] ),
87
+ 'name' => stripslashes( get_the_title( $data['id'] ) ),
88
+ 'mime' => stripslashes( get_post_mime_type( $data['id'] ) ),
89
+ 'title' => stripslashes( $data['title'] ),
90
+ 'caption' => stripslashes( $data['caption'] ),
91
+ 'filesize' => stripslashes( attachments_get_filesize_formatted( get_attached_file( $data['id'] ) ) ),
92
+ 'location' => stripslashes( wp_get_attachment_url( $data['id'] ) ),
93
+ 'order' => stripslashes( $data['order'] )
94
+ ));
95
+ }
96
+
97
+ // sort attachments
98
+ if( count( $post_attachments ) > 1 )
99
+ {
100
+ usort( $post_attachments, "attachments_cmp" );
101
+ }
102
+ }
103
+
104
+ return $post_attachments;
105
+ }
deprecated/images/handle.gif ADDED
Binary file
deprecated/images/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php
deprecated/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php
deprecated/js/attachments.js ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function($){
2
+ var context = false;
3
+ var thickbox_modder;
4
+
5
+ // init sortability
6
+ if($('div#attachments-list ul:data(sortable)').length==0&&$('div#attachments-list ul li').length>0){
7
+ $('div#attachments-list ul').sortable({
8
+ containment: 'parent',
9
+ stop: function(e, ui) {
10
+ $('#attachments-list ul li').each(function(i, id) {
11
+ $(this).find('input.attachment_order').val(i+1);
12
+ });
13
+ }
14
+ });
15
+ }
16
+
17
+ // delete link handler
18
+ function attachments_hook_delete_links(theparent){
19
+ attachment_parent = theparent.parent().parent().parent();
20
+ attachment_parent.slideUp(function() {
21
+ attachment_parent.remove();
22
+ $('#attachments-list ul li').each(function(i, id) {
23
+ $(this).find('input.attachment_order').val(i+1);
24
+ });
25
+ if($('div#attachments-list li').length == 0) {
26
+ $('#attachments-list').slideUp(function() {
27
+ $('#attachments-list').hide();
28
+ });
29
+ }
30
+ });
31
+ }
32
+
33
+ // Hook our delete links
34
+ if(parseFloat($.fn.jquery)>=1.7){
35
+ // 'live' is deprecated
36
+ $(document).on("click", "span.attachment-delete a", function(event){
37
+ theparent = $(this);
38
+ attachments_hook_delete_links(theparent);
39
+ return false;
40
+ });
41
+ }else{
42
+ $('span.attachment-delete a').live('click',function(event){
43
+ theparent = $(this);
44
+ attachments_hook_delete_links(theparent);
45
+ return false;
46
+ });
47
+ }
48
+
49
+
50
+
51
+ // thickbox handler
52
+ if(parseFloat($.fn.jquery)>=1.7){
53
+ // 'live' is deprecated
54
+ $(document).on("click", "a#attachments-thickbox", function(event){
55
+ event.preventDefault();
56
+ theparent = $(this);
57
+ attachments_handle_thickbox(event,theparent);
58
+ return false;
59
+ });
60
+ }else{
61
+ $('a#attachments-thickbox').live('click',function(event){
62
+ event.preventDefault();
63
+ theparent = $(this);
64
+ attachments_handle_thickbox(event,theparent);
65
+ return false;
66
+ });
67
+ }
68
+
69
+ function attachments_handle_thickbox(event,theparent){
70
+ var href = theparent.attr('href'), width = jQuery(window).width(), H = jQuery(window).height(), W = ( 720 < width ) ? 720 : width;
71
+ if ( ! href ) return;
72
+ href = href.replace(/&width=[0-9]+/g, '');
73
+ href = href.replace(/&height=[0-9]+/g, '');
74
+ theparent.attr( 'href', href + '&width=' + ( W - 80 ) + '&height=' + ( H - 85 ) );
75
+ context = true;
76
+ thickbox_modder = setInterval( function(){
77
+ if( context ){
78
+ modify_thickbox();
79
+ }
80
+ }, 500 );
81
+ tb_show('Attach a file', event.target.href, false);
82
+ return false;
83
+ }
84
+
85
+ // handle the attachment process
86
+ function handle_attach(title,caption,id,thumb){
87
+ var source = $('#attachment-template').html();
88
+ var template = Handlebars.compile(source);
89
+
90
+ var order = $('#attachments-list > ul > li').length + 1;
91
+
92
+ $('div#attachments-list ul', top.document).append(template({name:title,title:title,caption:caption,id:id,thumb:thumb,order:order}));
93
+
94
+ $('#attachments-list > ul > li').each(function(i, id) {
95
+ $(this).find('input.attachment_order').val(i+1);
96
+ });
97
+
98
+ return false;
99
+ }
100
+
101
+
102
+ function modify_thickbox(){
103
+
104
+ the_thickbox = jQuery('#TB_iframeContent').contents();
105
+
106
+ // our new click handler for the attach button
107
+ the_thickbox.find('td.savesend input').unbind('click').click(function(e){
108
+
109
+ jQuery(this).after('<span class="attachments-attached">Attached!</span>');
110
+
111
+ // grab our meta as per the Media library
112
+ var wp_media_meta = $(this).parent().parent().parent();
113
+ var wp_media_title = wp_media_meta.find('tr.post_title td.field input').val();
114
+ var wp_media_caption = wp_media_meta.find('tr.post_excerpt td.field input').val();
115
+ var wp_media_id = wp_media_meta.find('td.imgedit-response').attr('id').replace('imgedit-response-','');
116
+ var wp_media_thumb = wp_media_meta.parent().find('img.thumbnail').attr('src');
117
+
118
+ handle_attach(wp_media_title,wp_media_caption,wp_media_id,wp_media_thumb);
119
+
120
+ the_thickbox.find('span.attachments-attached').delay(1000).fadeOut('fast');
121
+ return false;
122
+ });
123
+ // update button
124
+ if(the_thickbox.find('.media-item .savesend input[type=submit], #insertonlybutton').length){
125
+ the_thickbox.find('.media-item .savesend input[type=submit], #insertonlybutton').val('Attach');
126
+ }
127
+ if(the_thickbox.find('#tab-type_url').length){
128
+ the_thickbox.find('#tab-type_url').hide();
129
+ }
130
+ if(the_thickbox.find('tr.post_title').length){
131
+ // we need to ALWAYS get the fullsize since we're retrieving the guid
132
+ // if the user inserts an image somewhere else and chooses another size, everything breaks
133
+ the_thickbox.find('tr.image-size input[value="full"]').prop('checked', true);
134
+ the_thickbox.find('tr.post_title,tr.image_alt,tr.post_excerpt,tr.image-size,tr.post_content,tr.url,tr.align,tr.submit>td>a.del-link').hide();
135
+ }
136
+
137
+ // was the thickbox closed?
138
+ if(the_thickbox.length==0 && context){
139
+ clearInterval(thickbox_modder);
140
+ context = false;
141
+ }
142
+ }
143
+
144
+ });
145
+
146
+
{js → deprecated/js}/handlebars.js RENAMED
File without changes
deprecated/js/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php
{languages → deprecated/languages}/attachments-fr_FR.mo RENAMED
File without changes
{languages → deprecated/languages}/attachments-fr_FR.po RENAMED
File without changes
{languages → deprecated/languages}/attachments-it_IT.mo RENAMED
File without changes
{languages → deprecated/languages}/attachments-it_IT.po RENAMED
File without changes
{languages → deprecated/languages}/attachments-pl_PL.mo RENAMED
File without changes
{languages → deprecated/languages}/attachments-pl_PL.po RENAMED
File without changes
{languages → deprecated/languages}/attachments-pt_BR.mo RENAMED
File without changes
{languages → deprecated/languages}/attachments-pt_BR.po RENAMED
File without changes
{languages → deprecated/languages}/attachments-sv_SE.mo RENAMED
File without changes
{languages → deprecated/languages}/attachments-sv_SE.po RENAMED
File without changes
deprecated/languages/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php
humans.txt ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* TEAM */
2
+ Name: Jonathan Christopher
3
+ Site: http://mondaybynoon.com
4
+ Title: Lead Developer
5
+ Twitter: @jchristopher
6
+ ADN: @jchristopher
7
+ Location: Troy, NY, USA
8
+
9
+ /* THANKS */
10
+ JR Tashjian http://jrtashjian.com
11
+
12
+ /* META */
13
+ Updated: 2012/12/01
14
+ Standards: HTML5, CSS3
15
+ Components: WordPress, jQuery, Underscore.js, Backbone.js
16
+ Software: Sublime Text 2
images/handle.gif CHANGED
Binary file
images/index.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Do not modify the files in this folder.
5
+ */
index.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Plugin Name: Attachments
5
+ * Plugin URI: https://github.com/jchristopher/attachments
6
+ * Description: Attachments gives the ability to append any number of Media Library items to Pages, Posts, and Custom Post Types
7
+ * Author: Jonathan Christopher
8
+ * Author URI: http://mondaybynoon.com/
9
+ * Version: 3.0.6
10
+ * Text Domain: attachments
11
+ * Domain Path: /languages/
12
+ * License: GPLv2 or later
13
+ * License URI: http://www.gnu.org/licenses/gpl-2.0.html
14
+ */
15
+
16
+ // Exit if accessed directly
17
+ if( !defined( 'ABSPATH' ) ) exit;
18
+
19
+ // Store whether or not we're in the admin
20
+ if( !defined( 'IS_ADMIN' ) ) define( 'IS_ADMIN', is_admin() );
21
+
22
+ // Environment check
23
+ $wp_version = get_bloginfo( 'version' );
24
+
25
+ if( !version_compare( PHP_VERSION, '5.2', '>=' ) && IS_ADMIN && ( !defined( 'DOING_AJAX' ) || !DOING_AJAX ) )
26
+ {
27
+ // failed PHP requirement
28
+ require_once ABSPATH . '/wp-admin/includes/plugin.php';
29
+ deactivate_plugins( __FILE__ );
30
+ wp_die( esc_attr( __( 'Attachments requires PHP 5.2+. Attachments has been automatically deactivated.' ) ) );
31
+ }
32
+ else
33
+ {
34
+ if( ( defined( 'ATTACHMENTS_LEGACY' ) && ATTACHMENTS_LEGACY === true ) || version_compare( $wp_version, '3.5', '<' ) )
35
+ {
36
+ // load deprecated version of Attachments
37
+ require_once 'deprecated/attachments.php';
38
+ }
39
+ else
40
+ {
41
+ define( 'ATTACHMENTS_DIR', plugin_dir_path( __FILE__ ) );
42
+ define( 'ATTACHMENTS_URL', plugin_dir_url( __FILE__ ) );
43
+
44
+ // load current version of Attachments
45
+ require_once 'classes/class.attachments.php';
46
+ }
47
+ }
js/attachments.js CHANGED
@@ -1,146 +1,90 @@
1
- jQuery(document).ready(function($){
2
- var context = false;
3
- var thickbox_modder;
4
-
5
- // init sortability
6
- if($('div#attachments-list ul:data(sortable)').length==0&&$('div#attachments-list ul li').length>0){
7
- $('div#attachments-list ul').sortable({
8
- containment: 'parent',
9
- stop: function(e, ui) {
10
- $('#attachments-list ul li').each(function(i, id) {
11
- $(this).find('input.attachment_order').val(i+1);
12
- });
13
- }
14
- });
15
- }
16
-
17
- // delete link handler
18
- function attachments_hook_delete_links(theparent){
19
- attachment_parent = theparent.parent().parent().parent();
20
- attachment_parent.slideUp(function() {
21
- attachment_parent.remove();
22
- $('#attachments-list ul li').each(function(i, id) {
23
- $(this).find('input.attachment_order').val(i+1);
24
- });
25
- if($('div#attachments-list li').length == 0) {
26
- $('#attachments-list').slideUp(function() {
27
- $('#attachments-list').hide();
28
- });
29
- }
30
- });
31
  }
32
-
33
- // Hook our delete links
34
- if(parseFloat($.fn.jquery)>=1.7){
35
- // 'live' is deprecated
36
- $(document).on("click", "span.attachment-delete a", function(event){
37
- theparent = $(this);
38
- attachments_hook_delete_links(theparent);
39
- return false;
40
- });
41
- }else{
42
- $('span.attachment-delete a').live('click',function(event){
43
- theparent = $(this);
44
- attachments_hook_delete_links(theparent);
45
- return false;
46
- });
47
  }
48
-
49
-
50
-
51
- // thickbox handler
52
- if(parseFloat($.fn.jquery)>=1.7){
53
- // 'live' is deprecated
54
- $(document).on("click", "a#attachments-thickbox", function(event){
55
- event.preventDefault();
56
- theparent = $(this);
57
- attachments_handle_thickbox(event,theparent);
58
- return false;
59
- });
60
- }else{
61
- $('a#attachments-thickbox').live('click',function(event){
62
- event.preventDefault();
63
- theparent = $(this);
64
- attachments_handle_thickbox(event,theparent);
65
- return false;
66
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
 
 
 
 
68
 
69
- function attachments_handle_thickbox(event,theparent){
70
- var href = theparent.attr('href'), width = jQuery(window).width(), H = jQuery(window).height(), W = ( 720 < width ) ? 720 : width;
71
- if ( ! href ) return;
72
- href = href.replace(/&width=[0-9]+/g, '');
73
- href = href.replace(/&height=[0-9]+/g, '');
74
- theparent.attr( 'href', href + '&width=' + ( W - 80 ) + '&height=' + ( H - 85 ) );
75
- context = true;
76
- thickbox_modder = setInterval( function(){
77
- if( context ){
78
- modify_thickbox();
79
- }
80
- }, 500 );
81
- tb_show('Attach a file', event.target.href, false);
82
- return false;
83
- }
84
-
85
- // handle the attachment process
86
- function handle_attach(title,caption,id,thumb){
87
- var source = $('#attachment-template').html();
88
- var template = Handlebars.compile(source);
89
-
90
- var order = $('#attachments-list > ul > li').length + 1;
91
-
92
- $('div#attachments-list ul', top.document).append(template({name:title,title:title,caption:caption,id:id,thumb:thumb,order:order}));
93
-
94
- $('#attachments-list > ul > li').each(function(i, id) {
95
- $(this).find('input.attachment_order').val(i+1);
96
- });
97
-
98
- return false;
99
- }
100
-
101
-
102
- function modify_thickbox(){
103
-
104
- the_thickbox = jQuery('#TB_iframeContent').contents();
105
-
106
- // our new click handler for the attach button
107
- the_thickbox.find('td.savesend input').unbind('click').click(function(e){
108
-
109
- jQuery(this).after('<span class="attachments-attached">Attached!</span>');
110
-
111
- // grab our meta as per the Media library
112
- var wp_media_meta = $(this).parent().parent().parent();
113
- var wp_media_title = wp_media_meta.find('tr.post_title td.field input').val();
114
- var wp_media_caption = wp_media_meta.find('tr.post_excerpt td.field input').val();
115
- var wp_media_id = wp_media_meta.find('td.imgedit-response').attr('id').replace('imgedit-response-','');
116
- var wp_media_thumb = wp_media_meta.parent().find('img.thumbnail').attr('src');
117
-
118
- handle_attach(wp_media_title,wp_media_caption,wp_media_id,wp_media_thumb);
119
-
120
- the_thickbox.find('span.attachments-attached').delay(1000).fadeOut('fast');
121
- return false;
122
- });
123
- // update button
124
- if(the_thickbox.find('.media-item .savesend input[type=submit], #insertonlybutton').length){
125
- the_thickbox.find('.media-item .savesend input[type=submit], #insertonlybutton').val('Attach');
126
- }
127
- if(the_thickbox.find('#tab-type_url').length){
128
- the_thickbox.find('#tab-type_url').hide();
129
- }
130
- if(the_thickbox.find('tr.post_title').length){
131
- // we need to ALWAYS get the fullsize since we're retrieving the guid
132
- // if the user inserts an image somewhere else and chooses another size, everything breaks
133
- the_thickbox.find('tr.image-size input[value="full"]').prop('checked', true);
134
- the_thickbox.find('tr.post_title,tr.image_alt,tr.post_excerpt,tr.image-size,tr.post_content,tr.url,tr.align,tr.submit>td>a.del-link').hide();
135
- }
136
-
137
- // was the thickbox closed?
138
- if(the_thickbox.length==0 && context){
139
- clearInterval(thickbox_modder);
140
- context = false;
141
- }
142
- }
143
-
144
- });
145
-
146
-
1
+ function attachments_uniqid (prefix, more_entropy) {
2
+ // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
3
+ // + revised by: Kankrelune (http://www.webfaktory.info/)
4
+ // % note 1: Uses an internal counter (in php_js global) to avoid collision
5
+ // * example 1: uniqid();
6
+ // * returns 1: 'a30285b160c14'
7
+ // * example 2: uniqid('foo');
8
+ // * returns 2: 'fooa30285b1cd361'
9
+ // * example 3: uniqid('bar', true);
10
+ // * returns 3: 'bara20285b23dfd1.31879087'
11
+ if (typeof prefix == 'undefined') {
12
+ prefix = "";
13
+ }
14
+
15
+ var retId;
16
+ var formatSeed = function (seed, reqWidth) {
17
+ seed = parseInt(seed, 10).toString(16); // to hex str
18
+ if (reqWidth < seed.length) { // so long we split
19
+ return seed.slice(seed.length - reqWidth);
 
 
 
 
 
 
 
 
 
 
 
20
  }
21
+ if (reqWidth > seed.length) { // so short we pad
22
+ return Array(1 + (reqWidth - seed.length)).join('0') + seed;
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  }
24
+ return seed;
25
+ };
26
+
27
+ // BEGIN REDUNDANT
28
+ if (!this.php_js) {
29
+ this.php_js = {};
30
+ }
31
+ // END REDUNDANT
32
+ if (!this.php_js.uniqidSeed) { // init seed with big random int
33
+ this.php_js.uniqidSeed = Math.floor(Math.random() * 0x75bcd15);
34
+ }
35
+ this.php_js.uniqidSeed++;
36
+
37
+ retId = prefix; // start with prefix, add current milliseconds hex string
38
+ retId += formatSeed(parseInt(new Date().getTime() / 1000, 10), 8);
39
+ retId += formatSeed(this.php_js.uniqidSeed, 5); // add seed hex string
40
+ if (more_entropy) {
41
+ // for more entropy we add a float lower to 10
42
+ retId += (Math.random() * 10).toFixed(8).toString();
43
+ }
44
+
45
+ return retId;
46
+ }
47
+
48
+ function attachments_isset () {
49
+ // http://kevin.vanzonneveld.net
50
+ // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
51
+ // + improved by: FremyCompany
52
+ // + improved by: Onno Marsman
53
+ // + improved by: Rafał Kukawski
54
+ // * example 1: isset( undefined, true);
55
+ // * returns 1: false
56
+ // * example 2: isset( 'Kevin van Zonneveld' );
57
+ // * returns 2: true
58
+ var a = arguments,
59
+ l = a.length,
60
+ i = 0,
61
+ undef;
62
+
63
+ if (l === 0) {
64
+ throw new Error('Empty isset');
65
+ }
66
+
67
+ while (i !== l) {
68
+ if (a[i] === undef || a[i] === null) {
69
+ return false;
70
  }
71
+ i++;
72
+ }
73
+ return true;
74
+ }
75
 
76
+ jQuery(document).ready(function($){
77
+ $( '.attachments-container' ).sortable({
78
+ placeholder: 'attachments-attachment-highlight',
79
+ opacity: 0.5,
80
+ forceHelperSize: true,
81
+ forcePlaceholderSize: true,
82
+ items: '> .attachments-attachment',
83
+ scroll: true,
84
+ tolerance: 'intersect',
85
+ axis: 'y',
86
+ containment: 'parent',
87
+ handle: '.attachments-handle img'
88
+ });
89
+ $( '.attachments-container' ).disableSelection();
90
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/index.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Do not modify the files in this folder.
5
+ */
languages/index.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Do not modify the files in this folder.
5
+ */
license.txt ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5
+ 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
6
+
7
+ Everyone is permitted to copy and distribute verbatim copies
8
+ of this license document, but changing it is not allowed.
9
+
10
+ Preamble
11
+
12
+ The licenses for most software are designed to take away your
13
+ freedom to share and change it. By contrast, the GNU General Public
14
+ License is intended to guarantee your freedom to share and change free
15
+ software--to make sure the software is free for all its users. This
16
+ General Public License applies to most of the Free Software
17
+ Foundation's software and to any other program whose authors commit to
18
+ using it. (Some other Free Software Foundation software is covered by
19
+ the GNU Library General Public License instead.) You can apply it to
20
+ your programs, too.
21
+
22
+ When we speak of free software, we are referring to freedom, not
23
+ price. Our General Public Licenses are designed to make sure that you
24
+ have the freedom to distribute copies of free software (and charge for
25
+ this service if you wish), that you receive source code or can get it
26
+ if you want it, that you can change the software or use pieces of it
27
+ in new free programs; and that you know you can do these things.
28
+
29
+ To protect your rights, we need to make restrictions that forbid
30
+ anyone to deny you these rights or to ask you to surrender the rights.
31
+ These restrictions translate to certain responsibilities for you if you
32
+ distribute copies of the software, or if you modify it.
33
+
34
+ For example, if you distribute copies of such a program, whether
35
+ gratis or for a fee, you must give the recipients all the rights that
36
+ you have. You must make sure that they, too, receive or can get the
37
+ source code. And you must show them these terms so they know their
38
+ rights.
39
+
40
+ We protect your rights with two steps: (1) copyright the software, and
41
+ (2) offer you this license which gives you legal permission to copy,
42
+ distribute and/or modify the software.
43
+
44
+ Also, for each author's protection and ours, we want to make certain
45
+ that everyone understands that there is no warranty for this free
46
+ software. If the software is modified by someone else and passed on, we
47
+ want its recipients to know that what they have is not the original, so
48
+ that any problems introduced by others will not reflect on the original
49
+ authors' reputations.
50
+
51
+ Finally, any free program is threatened constantly by software
52
+ patents. We wish to avoid the danger that redistributors of a free
53
+ program will individually obtain patent licenses, in effect making the
54
+ program proprietary. To prevent this, we have made it clear that any
55
+ patent must be licensed for everyone's free use or not licensed at all.
56
+
57
+ The precise terms and conditions for copying, distribution and
58
+ modification follow.
59
+
60
+ GNU GENERAL PUBLIC LICENSE
61
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
62
+
63
+ 0. This License applies to any program or other work which contains
64
+ a notice placed by the copyright holder saying it may be distributed
65
+ under the terms of this General Public License. The "Program", below,
66
+ refers to any such program or work, and a "work based on the Program"
67
+ means either the Program or any derivative work under copyright law:
68
+ that is to say, a work containing the Program or a portion of it,
69
+ either verbatim or with modifications and/or translated into another
70
+ language. (Hereinafter, translation is included without limitation in
71
+ the term "modification".) Each licensee is addressed as "you".
72
+
73
+ Activities other than copying, distribution and modification are not
74
+ covered by this License; they are outside its scope. The act of
75
+ running the Program is not restricted, and the output from the Program
76
+ is covered only if its contents constitute a work based on the
77
+ Program (independent of having been made by running the Program).
78
+ Whether that is true depends on what the Program does.
79
+
80
+ 1. You may copy and distribute verbatim copies of the Program's
81
+ source code as you receive it, in any medium, provided that you
82
+ conspicuously and appropriately publish on each copy an appropriate
83
+ copyright notice and disclaimer of warranty; keep intact all the
84
+ notices that refer to this License and to the absence of any warranty;
85
+ and give any other recipients of the Program a copy of this License
86
+ along with the Program.
87
+
88
+ You may charge a fee for the physical act of transferring a copy, and
89
+ you may at your option offer warranty protection in exchange for a fee.
90
+
91
+ 2. You may modify your copy or copies of the Program or any portion
92
+ of it, thus forming a work based on the Program, and copy and
93
+ distribute such modifications or work under the terms of Section 1
94
+ above, provided that you also meet all of these conditions:
95
+
96
+ a) You must cause the modified files to carry prominent notices
97
+ stating that you changed the files and the date of any change.
98
+
99
+ b) You must cause any work that you distribute or publish, that in
100
+ whole or in part contains or is derived from the Program or any
101
+ part thereof, to be licensed as a whole at no charge to all third
102
+ parties under the terms of this License.
103
+
104
+ c) If the modified program normally reads commands interactively
105
+ when run, you must cause it, when started running for such
106
+ interactive use in the most ordinary way, to print or display an
107
+ announcement including an appropriate copyright notice and a
108
+ notice that there is no warranty (or else, saying that you provide
109
+ a warranty) and that users may redistribute the program under
110
+ these conditions, and telling the user how to view a copy of this
111
+ License. (Exception: if the Program itself is interactive but
112
+ does not normally print such an announcement, your work based on
113
+ the Program is not required to print an announcement.)
114
+
115
+ These requirements apply to the modified work as a whole. If
116
+ identifiable sections of that work are not derived from the Program,
117
+ and can be reasonably considered independent and separate works in
118
+ themselves, then this License, and its terms, do not apply to those
119
+ sections when you distribute them as separate works. But when you
120
+ distribute the same sections as part of a whole which is a work based
121
+ on the Program, the distribution of the whole must be on the terms of
122
+ this License, whose permissions for other licensees extend to the
123
+ entire whole, and thus to each and every part regardless of who wrote it.
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
+
readme.txt CHANGED
@@ -3,8 +3,10 @@ Contributors: jchristopher
3
  Donate link: http://mondaybynoon.com/donate/
4
  Tags: post, page, posts, pages, images, PDF, doc, Word, image, jpg, jpeg, picture, pictures, photos, attachment
5
  Requires at least: 3.0
6
- Tested up to: 3.4.1
7
- Stable tag: 1.6.2.1
 
 
8
 
9
  Attachments allows you to simply append any number of items from your WordPress Media Library to Posts, Pages, and Custom Post Types
10
 
@@ -12,12 +14,48 @@ Attachments allows you to simply append any number of items from your WordPress
12
 
13
  Attachments allows you to simply append any number of items from your WordPress Media Library to Posts, Pages, and Custom Post Types. This plugin *does not* directly interact with your theme, you will need to edit your template files.
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  == Installation ==
16
 
17
  1. Download the plugin and extract the files
18
  1. Upload `attachments` to your `~/wp-content/plugins/` directory
19
  1. Activate the plugin through the 'Plugins' menu in WordPress
20
- 1. View the Attachments settings (located under the main Settings menu in the WordPress admin) and turn on Attachments for your desired post types
21
  1. Update your templates where applicable (see **Usage**)
22
 
23
  == Frequently Asked Questions ==
@@ -30,6 +68,14 @@ You need to turn on Attachments for your post types. View the Attachments settin
30
 
31
  You will need to edit your theme files where applicable. Please reference the **Usage** instructions.
32
 
 
 
 
 
 
 
 
 
33
  = Where are uploads saved? =
34
 
35
  Attachments uses WordPress' built in Media library for uploads and storage.
@@ -40,12 +86,52 @@ Attachments uses WordPress' built in Media library for uploads and storage.
40
 
41
  == Screenshots ==
42
 
43
- 1. Attachments meta box as it appears on Posts, Pages, or Custom Post Types
44
- 2. Native WordPress browse modal dialog, slightly customized for Attachments. Upload straight from your computer.
45
- 4. Once assets have been attached, you can customize the title, caption, and order
 
 
46
 
47
  == Changelog ==
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  = 1.6.2.1 =
50
  * Fixed an issue with Handlebars in Firefox
51
  * Better handling of Attachment name
@@ -177,6 +263,13 @@ Attachments uses WordPress' built in Media library for uploads and storage.
177
 
178
  == Upgrade Notice ==
179
 
 
 
 
 
 
 
 
180
  = 1.0.8 =
181
  As always, be sure to back up your database and files before upgrading.
182
 
@@ -187,40 +280,129 @@ Attachments are now stored in such a way that removes an in-place limitation on
187
 
188
  Planned feature additions include:
189
 
190
- * Update Settings to use official Settings API
 
 
 
 
 
 
 
 
 
191
 
192
  == Usage ==
193
 
194
- After installing Attachments, you will need to update your template files in order to pull the data to the front end.
195
 
196
- To pull all Attachments for a Post or Page, fire `attachments_get_attachments()`. There is one optional parameter which can force a Post ID if `attachments_get_attachments()` is fired outside The Loop. If used inside The Loop, all Attachments will be pulled for the current Post or Page.
 
197
 
198
- Firing `attachments_get_attachments()` returns an array consisting of all available Attachments. Currently each Attachment has four pieces of data available:
199
 
200
- * **title** - The attachment Title
201
- * **caption** - The attachment Caption
202
- * **id** - The WordPress assigned attachment id (for use with other WordPress media functions)
203
- * **location** - The attachment URI
204
- * **mime** - The attachment MIME type (as defined by WordPress)
205
- * **filesize** - Formatted file size
206
 
207
- Here is a basic implementation:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
 
209
  `<?php
210
- if( function_exists( 'attachments_get_attachments' ) )
211
- {
212
- $attachments = attachments_get_attachments();
213
- $total_attachments = count( $attachments );
214
- if( $total_attachments ) : ?>
215
- <ul>
216
- <?php for( $i=0; $i<$total_attachments; $i++ ) : ?>
217
- <li><?php echo $attachments[$i]['title']; ?></li>
218
- <li><?php echo $attachments[$i]['caption']; ?></li>
219
- <li><?php echo $attachments[$i]['id']; ?></li>
220
- <li><?php echo $attachments[$i]['location']; ?></li>
221
- <li><?php echo $attachments[$i]['mime']; ?></li>
222
- <li><?php echo $attachments[$i]['filesize']; ?></li>
223
- <?php endfor; ?>
224
- </ul>
225
- <?php endif; ?>
226
- <?php } ?>`
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  Donate link: http://mondaybynoon.com/donate/
4
  Tags: post, page, posts, pages, images, PDF, doc, Word, image, jpg, jpeg, picture, pictures, photos, attachment
5
  Requires at least: 3.0
6
+ Tested up to: 3.5
7
+ Stable tag: 3.0.6
8
+ License: GPLv2 or later
9
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
11
  Attachments allows you to simply append any number of items from your WordPress Media Library to Posts, Pages, and Custom Post Types
12
 
14
 
15
  Attachments allows you to simply append any number of items from your WordPress Media Library to Posts, Pages, and Custom Post Types. This plugin *does not* directly interact with your theme, you will need to edit your template files.
16
 
17
+ = Updated for WordPress 3.5! =
18
+
19
+ WordPress 3.5 ships with an amazing new Media workflow and Attachments 3.0 makes great use of it. *If you are not running WordPress 3.5, version 1.6.2.1 will be used until you upgrade to WordPress 3.5.*
20
+
21
+ = Associate Media items with posts =
22
+
23
+ The idea behind Attachments is to give developers the ability to directly associate Media items with any post. This is accomplished by adding a meta box to post edit screens as determined by the developer. Once Media items have been associated with a post, you're able to retrieve those Attachments and include them directly within your template files using any specific markup you wish.
24
+
25
+ = Integrate Attachments within your theme with fine grained control =
26
+
27
+ **Attachments does not automatically integrate itself with your theme.** Since the idea behind Attachments is to allow integration of Media within posts using developer-crafted, unique markup, *it's up to you to integrate with your theme*. The most basic integration includes editing the [appropriate template file](http://codex.wordpress.org/Template_Hierarchy) and adding your call(s) to Attachments. For example, if you have set up Attachments to be used with your Posts entries, edit `single.php` to include the following within The Loop:
28
+
29
+ `<?php $attachments = new Attachments( 'attachments' ); /* pass the instance name */ ?>
30
+ <?php if( $attachments->exist() ) : ?>
31
+ <h3>Attachments</h3>
32
+ <ul>
33
+ <?php while( $attachments->get() ) : ?>
34
+ <li>
35
+ ID: <?php echo $attachments->id(); ?><br />
36
+ Type: <?php echo $attachments->type(); ?><br />
37
+ Subtype: <?php echo $attachments->subtype(); ?><br />
38
+ URL: <?php echo $attachments->url(); ?><br />
39
+ Image: <?php echo $attachments->image( 'thumbnail' ); ?><br />
40
+ Source: <?php echo $attachments->src( 'full' ); ?><br />
41
+ Size: <?php echo $attachments->filesize(); ?><br />
42
+ Title Field: <?php echo $attachments->field( 'title' ); ?><br />
43
+ Caption Field: <?php echo $attachments->field( 'caption' ); ?>
44
+ </li>
45
+ <?php endwhile; ?>
46
+ </ul>
47
+ <?php endif; ?>`
48
+
49
+ That snippet will request all of the existing Attachments defined for the current Post within The Loop, and retrieve each itemized property for that Attachment. Using the provided details you're able to integrate the attached Media items in any way you please.
50
+
51
+ There is a lot more information on [Attachments' GitHub page](https://github.com/jchristopher/attachments). Please contribute!
52
+
53
  == Installation ==
54
 
55
  1. Download the plugin and extract the files
56
  1. Upload `attachments` to your `~/wp-content/plugins/` directory
57
  1. Activate the plugin through the 'Plugins' menu in WordPress
58
+ 1. Implement Attachments in your theme's `functions.php` or your own plugin (see **Usage**)
59
  1. Update your templates where applicable (see **Usage**)
60
 
61
  == Frequently Asked Questions ==
68
 
69
  You will need to edit your theme files where applicable. Please reference the **Usage** instructions.
70
 
71
+ = How do I disable the default Attachments meta box? =
72
+
73
+ You will need to edit your Attachments configuration. Please reference the **Usage** instructions.
74
+
75
+ = How do I change the fields for each Attachment? =
76
+
77
+ You will need to edit your Attachments configuration. Please reference the **Usage** instructions.
78
+
79
  = Where are uploads saved? =
80
 
81
  Attachments uses WordPress' built in Media library for uploads and storage.
86
 
87
  == Screenshots ==
88
 
89
+ 1. An Attachments meta box sitting below the content editor
90
+ 2. Direct integration with WordPress 3.5+ Media
91
+ 3. Attach multiple files at once
92
+ 4. Custom fields for each Attachment
93
+ 5. Drag and drop to sort
94
 
95
  == Changelog ==
96
 
97
+ = 3.0.6 =
98
+ * Fixed a possible JavaScript error if an Attachment that's an image doesn't have a proper thumbnail URL
99
+ * Added a total() method that will return the number of Attachments for the current instance
100
+ * When requesting the image() for a non-image Attachment, the WordPress-defined icon will be returned
101
+ * Added an icon() method that will return the WordPress-defined icon for the Attachment
102
+ * Cleaned up a PHP Warning when trying to save for an undefined field type
103
+ * Fixed an issue where template tags would be output for non-image Attachments after saving
104
+
105
+ = 3.0.5 =
106
+ * Fixed a regression in handling Custom Post Type names that would too aggressively interfere with instance regustration
107
+ * Fixed an issue when working with non-image Attachments
108
+
109
+ = 3.0.4 =
110
+ * Fixed an issue that prevented the choosing of a Featured Image for a Custom Post Type if Attachments was activated
111
+ * Attachments now only enqueues its assets on edit screens that actually utilize Attachments
112
+ * Fixed a potential JavaScript error triggered when a 'thumbnail' image size was not available
113
+ * Prevented incorrect usage of dashes used in CPT names for post_type argument when registering Attachments instances (fixes an integration issue with WP e-Commerce)
114
+ * Prevented re-running of migration process to avoid duplicates (e.g. on browser reload)
115
+
116
+ = 3.0.3 =
117
+ * Fixed an issue that prevented defining a post ID when retrieving Attachments outside The Loop
118
+ * Cleaned up potential PHP warning when Attachments were requested for a post that had none
119
+
120
+ = 3.0.2 =
121
+ * Fixed an issue where some HTML entities were not properly stored
122
+
123
+ = 3.0.1 =
124
+ * Fixed an issue where legacy mode was always enabled
125
+
126
+ = 3.0 =
127
+ * **Major** rewrite. After three years of development, Attachments has been rewritten to make
128
+ even better use of what WordPress has to offer
129
+ * Utilizes the brand spanking new 3.5 Media workflow
130
+ * Configuration now takes place within your theme or a plugin
131
+ * Multiple meta boxes! You can segment groups of Attachments with new instances, each unique
132
+ * Dynamic fields! You can manipulate which fields each instance uses
133
+ * File type limits. Limit which files are available to Attachments (e.g. images, audio, video)
134
+
135
  = 1.6.2.1 =
136
  * Fixed an issue with Handlebars in Firefox
137
  * Better handling of Attachment name
263
 
264
  == Upgrade Notice ==
265
 
266
+ = 3.0 =
267
+ **You will need to update your theme files that use Attachments 3.0**. Version 1.x of Attachments has been *fully deprecated* but is still available. If you would like to continue to use the (no longer supported) 1.x version you may add the following to your wp-config.php:
268
+
269
+ `define( 'ATTACHMENTS_LEGACY', true ); // force the legacy version of Attachments`
270
+
271
+ Version 3 is a *major* rewrite. While I've taken precautions in ensuring you won't lose any saved data it is important to back up your databse prior to upgrading in case something goes wrong. This version is a complete rewrite so all legacy data will be left in place, but a migration must take place to match the new data storage model and workflow.
272
+
273
  = 1.0.8 =
274
  As always, be sure to back up your database and files before upgrading.
275
 
280
 
281
  Planned feature additions include:
282
 
283
+ * Additional field type: textarea
284
+ * Additional field type: WYSIWYG
285
+ * Additional field type: checkbox
286
+ * Additional field type: radio
287
+ * Additional field type: select
288
+ * User-defined limiting the number of Attachments per instance
289
+ * User-defined custom field types
290
+ * Additional hooks/actions from top to bottom
291
+ * Shortcode(s)
292
+ * Output templates
293
 
294
  == Usage ==
295
 
296
+ When Attachments is first activated, a default instance is created titled Attachments. It has two fields:
297
 
298
+ 1. Title
299
+ 1. Caption
300
 
301
+ If you would like to *disable the default instance* (meta box titled 'Attachments' with a 'Title' and 'Caption' field) add the following to your `wp-config.php`:
302
 
303
+ `define( 'ATTACHMENTS_DEFAULT_INSTANCE', false );`
 
 
 
 
 
304
 
305
+ You may create instances with your own custom fields by using the `attachments_register` action. To create your own instance add the following to your theme's `functions.php` or your own plugin:
306
+
307
+ `<?php
308
+ function my_attachments( $attachments )
309
+ {
310
+ $args = array(
311
+
312
+ // title of the meta box (string)
313
+ 'label' => 'My Attachments',
314
+
315
+ // all post types to utilize (string|array)
316
+ 'post_type' => array( 'post', 'page' ),
317
+
318
+ // allowed file type(s) (array) (image|video|text|audio|application)
319
+ 'filetype' => null, // no filetype limit
320
+
321
+ // include a note within the meta box (string)
322
+ 'note' => 'Attach files here!',
323
+
324
+ // text for 'Attach' button (string)
325
+ 'button_text' => __( 'Attach Files', 'attachments' ),
326
+
327
+ // text for modal 'Attach' button (string)
328
+ 'modal_text' => __( 'Attach', 'attachments' ),
329
+
330
+ // fields for this instance (array)
331
+ 'fields' => array(
332
+ array(
333
+ 'name' => 'title', // unique field name
334
+ 'type' => 'text', // registered field type (field available in 3.0: text)
335
+ 'label' => __( 'Title', 'attachments' ), // label to display
336
+ ),
337
+ array(
338
+ 'name' => 'caption', // unique field name
339
+ 'type' => 'text', // registered field type (field available in 3.0: text)
340
+ 'label' => __( 'Caption', 'attachments' ), // label to display
341
+ ),
342
+ array(
343
+ 'name' => 'copyright', // unique field name
344
+ 'type' => 'text', // registered field type (field available in 3.0: text)
345
+ 'label' => __( 'Copyright', 'attachments' ), // label to display
346
+ ),
347
+ ),
348
+
349
+ );
350
+
351
+ $attachments->register( 'my_attachments', $args ); // unique instance name
352
+ }
353
+
354
+ add_action( 'attachments_register', 'my_attachments' );`
355
+
356
+ Once your instances are set up and working, you'll also need to edit your theme's template files to pull the data to the front end. To retrieve the Attachments for the current post, add this within The Loop:
357
+
358
+ `<?php $attachments = new Attachments( 'attachments' ); /* pass the instance name */ ?>
359
+ <?php if( $attachments->exist() ) : ?>
360
+ <h3>Attachments</h3>
361
+ <ul>
362
+ <?php while( $attachment = $attachments->get() ) : ?>
363
+ <li>
364
+ <pre><?php print_r( $attachment ); ?></pre>
365
+ </li>
366
+ <?php endwhile; ?>
367
+ </ul>
368
+ <?php endif; ?>`
369
+
370
+ If you want to get the Attachments for a post **outside The Loop**, add a second parameter with the post ID when instantiating Attachments:
371
 
372
  `<?php
373
+ // retrieve all Attachments for the 'attachments' instance of post 123
374
+ $attachments = new Attachments( 'attachments', 123 );
375
+ ?>
376
+ <?php if( $attachments->exist() ) : ?>
377
+ <h3>Attachments</h3>
378
+ <ul>
379
+ <?php while( $attachment = $attachments->get() ) : ?>
380
+ <li>
381
+ <pre><?php print_r( $attachment ); ?></pre>
382
+ </li>
383
+ <?php endwhile; ?>
384
+ </ul>
385
+ <?php endif; ?>`
386
+
387
+ You can also retrieve various attributes of the current Attachment using these utility functions:
388
+
389
+ `<?php $attachments = new Attachments( 'attachments' ); /* pass the instance name */ ?>
390
+ <?php if( $attachments->exist() ) : ?>
391
+ <h3>Attachments</h3>
392
+ <p>Total Attachments: <?php echo $attachments->total(); ?></p>
393
+ <ul>
394
+ <?php while( $attachments->get() ) : ?>
395
+ <li>
396
+ ID: <?php echo $attachments->id(); ?><br />
397
+ Type: <?php echo $attachments->type(); ?><br />
398
+ Subtype: <?php echo $attachments->subtype(); ?><br />
399
+ URL: <?php echo $attachments->url(); ?><br />
400
+ Image: <?php echo $attachments->image( 'thumbnail' ); ?><br />
401
+ Source: <?php echo $attachments->src( 'full' ); ?><br />
402
+ Size: <?php echo $attachments->filesize(); ?><br />
403
+ Title Field: <?php echo $attachments->field( 'title' ); ?><br />
404
+ Caption Field: <?php echo $attachments->field( 'caption' ); ?>
405
+ </li>
406
+ <?php endwhile; ?>
407
+ </ul>
408
+ <?php endif; ?>`
screenshot-1.jpg DELETED
Binary file
screenshot-2.jpg DELETED
Binary file
screenshot-3.jpg DELETED
Binary file
upgrade.php ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <?php
2
+
3
+ // nothing yet
views/index.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php
views/options.php ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Exit if accessed directly
4
+ if( !defined( 'ABSPATH' ) ) exit;
5
+
6
+ /**
7
+ * Migrate Attachments 1.x records to 3.0's format
8
+ *
9
+ * @since 3.0
10
+ */
11
+ function attachments_migrate( $instance = null, $title = null, $caption = null )
12
+ {
13
+ // sanitize
14
+ if( is_null( $instance ) || empty( $instance ) || is_null( $title ) || is_null( $caption ) )
15
+ return false;
16
+
17
+ $instance = str_replace( '-', '_', sanitize_title( $instance ) );
18
+ $title = empty( $title ) ? false : str_replace( '-', '_', sanitize_title( $title ) );
19
+ $caption = empty( $caption ) ? false : str_replace( '-', '_', sanitize_title( $caption ) );
20
+
21
+ // we need our deprecated functions
22
+ include_once( ATTACHMENTS_DIR . '/deprecated/get-attachments.php' );
23
+
24
+ // grab all of the posts we need to migrate
25
+ $query = new WP_Query( 'post_type=any&post_status=any&posts_per_page=-1&meta_key=_attachments' );
26
+
27
+ $count = 0;
28
+
29
+ // loop through each post
30
+ while( $query->have_posts() )
31
+ {
32
+ // set up postdata
33
+ $query->the_post();
34
+
35
+ // let's first decode our Attachments data
36
+ $existing_attachments = get_post_meta( $query->post->ID, '_attachments', false );
37
+
38
+ $post_attachments = array();
39
+
40
+ // check to make sure we've got data
41
+ if( is_array( $existing_attachments ) && count( $existing_attachments ) > 0 )
42
+ {
43
+ // loop through each existing attachment
44
+ foreach( $existing_attachments as $attachment )
45
+ {
46
+ // decode and unserialize the data
47
+ $data = unserialize( base64_decode( $attachment ) );
48
+
49
+ array_push( $post_attachments, array(
50
+ 'id' => stripslashes( $data['id'] ),
51
+ 'title' => stripslashes( $data['title'] ),
52
+ 'caption' => stripslashes( $data['caption'] ),
53
+ 'order' => stripslashes( $data['order'] )
54
+ ));
55
+ }
56
+
57
+ // sort attachments
58
+ if( count( $post_attachments ) > 1 )
59
+ {
60
+ usort( $post_attachments, 'attachments_cmp' );
61
+ }
62
+ }
63
+
64
+ // we have our Attachments entries
65
+
66
+ // let's check to see if we're migrating after population has taken place
67
+ $existing_attachments = get_post_meta( $query->post->ID, 'attachments', false );
68
+
69
+ if( !isset( $existing_attachments[0] ) )
70
+ $existing_attachments[0] = '';
71
+
72
+ $existing_attachments = json_decode( $existing_attachments[0] );
73
+
74
+ if( !is_object( $existing_attachments ) )
75
+ $existing_attachments = new stdClass();
76
+
77
+ // we'll loop through the legacy Attachments and save them in the new format
78
+ foreach( $post_attachments as $legacy_attachment )
79
+ {
80
+ // convert to the new format
81
+ $converted_attachment = array( 'id' => $legacy_attachment['id'] );
82
+
83
+ // fields are technically optional so we'll add those separately
84
+ // we're also going to encode them in the same way the main class does
85
+ if( $title )
86
+ $converted_attachment['fields'][$title] = htmlentities( stripslashes( $legacy_attachment['title'] ), ENT_QUOTES );
87
+
88
+ if( $caption )
89
+ $converted_attachment['fields'][$caption] = htmlentities( stripslashes( $legacy_attachment['caption'] ), ENT_QUOTES );
90
+
91
+ // check to see if the existing Attachments have our target instance
92
+ if( !isset( $existing_attachments->$instance ) )
93
+ {
94
+ // the instance doesn't exist so we need to create it
95
+ $existing_attachments->$instance = array();
96
+ }
97
+
98
+ // we need to convert our array to an object
99
+ $converted_attachment['fields'] = (object) $converted_attachment['fields'];
100
+ $converted_attachment = (object) $converted_attachment;
101
+
102
+ // append this legacy attachment to the existing instance
103
+ array_push( $existing_attachments->$instance, $converted_attachment );
104
+ }
105
+
106
+ // we're done! let's save everything in our new format
107
+ $existing_attachments = json_encode( $existing_attachments );
108
+
109
+ // save it to the database
110
+ update_post_meta( $query->post->ID, 'attachments', $existing_attachments );
111
+
112
+ // increment our counter
113
+ $count++;
114
+ }
115
+
116
+ return $count;
117
+ }
118
+
119
+ if( isset( $_GET['dismiss'] ) )
120
+ {
121
+ if( !wp_verify_nonce( $_GET['nonce'], 'attachments-dismiss') ) wp_die( __( 'Invalid request', 'attachments' ) );
122
+
123
+ add_option( 'attachments_ignore_migration', true, '', 'no' );
124
+ }
125
+ ?>
126
+
127
+ <div class="wrap">
128
+
129
+ <div id="icon-options-general" class="icon32"><br /></div>
130
+
131
+ <h2><?php _e( 'Attachments', 'attachments' ); ?></h2>
132
+
133
+ <?php if( isset( $_GET['overview'] ) ) : ?>
134
+
135
+ <div class="message updated" id="message">
136
+ <p><?php _e( "<strong>Attachments has changed significantly since it's last update.</strong> These changes <em>will affect your themes and plugins</em>.", 'attachments' ); ?></p>
137
+ </div>
138
+
139
+ <h4><?php _e( 'Immediate Reversal to Attachments 1.x', 'attachments' ); ?></h4>
140
+
141
+ <p><?php _e( 'If you would like to immediately <em>revert to the old version of Attachments</em> you may do so by downgrading the plugin install itself, or adding the following to your', 'attachments' ); ?> <code>wp-config.php</code>:</p>
142
+
143
+ <pre><code>define( 'ATTACHMENTS_LEGACY', true );</code></pre>
144
+
145
+ <h2><?php _e( 'Overview of changes from Attachments 1.x', 'attachments' ); ?></h2>
146
+
147
+ <p><?php _e( "A lot has changed since Attachments 1.x. The entire codebase was rewritten to not only make better use of the stellar Media updates in WordPress 3.5, but to also facilitate some exciting features coming down the line. With this rewrite came significant changes to the way you will work with Attachments. One of the biggest changes in Attachments 3.0 is the ability to create multiple meta boxes of Attachments, each with any number of custom fields you define. By default, Attachments will re-implement the meta box you've been using until now, but <strong>you will need to trigger a migration to the new format</strong>.", 'attachments' ); ?></p>
148
+
149
+ <h3><?php _e( 'Migrating Attachments 1.x data to Attachments 3.x', 'attachments' ); ?></h3>
150
+
151
+ <p><?php _e( "If you have existing Attachments 1.x data and are using it, a migration script has been bundled here and you can use it below. If you would like to directly migrate from Attachments 1.x to Attachments 3.x you can use the defaults put in place and your data will be migrated to the new format quickly and easily. Alternatively, if you'd like to customize the fields you're using a bit, you can do that first and then adjust the migration parameters to map the old fields to your new ones.", 'attachments' ); ?></p>
152
+
153
+ <h3><?php _e( 'Setting up Instances', 'attachments' ); ?></h3>
154
+
155
+ <p><?php _e( 'Attachments 3.0 ships with what are called <em>instances</em>. An instance is equivalent to a meta box on an edit screen and it has a number of properties you can customize. Please read the README for more information.', 'attachments' ); ?> <a href="https://github.com/jchristopher/attachments/blob/master/README.md#usage"><?php _e( 'Additinoal instructions', 'attachments' ); ?>.</a></p>
156
+
157
+ <h3><?php _e( 'Retrieving Attachments in your theme', 'attachments' ); ?></h3>
158
+
159
+ <p><?php _e( 'As always has been the case with Attachments, editing your theme files is required. The syntax to do so has changed in Attachments 3.0. Please read the', 'attachments' ); ?> <a href="https://github.com/jchristopher/attachments/blob/master/README.md#usage"><?php _e( 'Additinoal instructions', 'attachments' ); ?></a>.</p>
160
+
161
+ <form action="options-general.php" method="get">
162
+ <input type="hidden" name="page" value="attachments" />
163
+ <input type="hidden" name="dismiss" value="1" />
164
+ <input type="hidden" name="nonce" value="<?php echo wp_create_nonce( 'attachments-dismiss' ); ?>" />
165
+
166
+ <p class="submit">
167
+ <input type="submit" name="submit" id="submit" class="button button-secondary" value="<?php esc_attr_e( 'Dismiss these notices without migrating', 'attachments' ); ?>" />
168
+ </p>
169
+ </form>
170
+
171
+ <?php endif; ?>
172
+
173
+ <?php
174
+
175
+ // check for any legacy Attachments
176
+ $legacy = new WP_Query( 'post_type=any&post_status=any&posts_per_page=1&meta_key=_attachments' );
177
+
178
+ // check to see if we're migrating
179
+ if( isset( $_GET['migrate'] ) )
180
+ {
181
+ switch( intval( $_GET['migrate'] ) )
182
+ {
183
+ case 1:
184
+ if( !wp_verify_nonce( $_GET['nonce'], 'attachments-migrate-1') ) wp_die( __( 'Invalid request', 'attachments' ) );
185
+ ?>
186
+ <h3><?php _e( 'Migration Step 1', 'attachments' ); ?></h3>
187
+ <p><?php _e( "In order to migrate Attachments 1.x data, you need to set which instance and fields in version 3.0+ you'd like to use:", 'attachments' ); ?></p>
188
+ <form action="options-general.php" method="get">
189
+ <input type="hidden" name="page" value="attachments" />
190
+ <input type="hidden" name="migrate" value="2" />
191
+ <input type="hidden" name="nonce" value="<?php echo wp_create_nonce( 'attachments-migrate-2' ); ?>" />
192
+ <table class="form-table">
193
+ <tbody>
194
+ <tr valign="top">
195
+ <th scope="row">
196
+ <label for="attachments-instance"><?php _e( 'Attachments 3.x Instance', 'attachments' ); ?></label>
197
+ </th>
198
+ <td>
199
+ <input name="attachments-instance" id="attachments-instance" value="attachments" class="regular-text" />
200
+ <p class="description"><?php _e( 'The instance name you would like to use in the migration. Required.', 'attachments' ); ?></p>
201
+ </td>
202
+ </tr>
203
+ <tr valign="top">
204
+ <th scope="row">
205
+ <label for="attachments-title"><?php _e( 'Attachments 3.x Title', 'attachments' ); ?></label>
206
+ </th>
207
+ <td>
208
+ <input name="attachments-title" id="attachments-title" value="title" class="regular-text" />
209
+ <p class="description"><?php _e( 'The <code>Title</code> field data will be migrated to this field name in Attachments 3.x. Leave empty to disregard.', 'attachments' ); ?></p>
210
+ </td>
211
+ </tr>
212
+ <tr valign="top">
213
+ <th scope="row">
214
+ <label for="attachments-caption"><?php _e( 'Attachments 3.x Caption', 'attachments' ); ?></label>
215
+ </th>
216
+ <td>
217
+ <input name="attachments-caption" id="attachments-caption" value="caption" class="regular-text" />
218
+ <p class="description"><?php _e( 'The <code>Caption</code> field data will be migrated to this field name in Attachments 3.x. Leave empty to disregard.', 'attachments' ); ?></p>
219
+ </td>
220
+ </tr>
221
+ </tbody>
222
+ </table>
223
+ <p class="submit">
224
+ <input type="submit" name="submit" id="submit" class="button button-primary" value="<?php esc_attr_e( 'Start Migration', 'attachments' ); ?>" />
225
+ </p>
226
+ </form>
227
+ <?php
228
+ break;
229
+
230
+ case 2:
231
+ if( !wp_verify_nonce( $_GET['nonce'], 'attachments-migrate-2') ) wp_die( __( 'Invalid request', 'attachments' ) );
232
+
233
+ $total = attachments_migrate( $_GET['attachments-instance'], $_GET['attachments-title'], $_GET['attachments-caption'] );
234
+
235
+ if( false == get_option( 'attachments_migrated' ) ) :
236
+ ?>
237
+ <h3><?php _e( 'Migration Complete!', 'attachments' ); ?></h3>
238
+ <p><?php _e( 'The migration has completed.', 'attachments' ); ?> <strong><?php _e( 'Migrated', 'attachments'); ?>: <?php echo $total; ?></strong>.</p>
239
+ <?php else : ?>
240
+ <h3><?php _e( 'Migration Already Run!', 'attachments' ); ?></h3>
241
+ <p><?php _e( 'The migration has already been run. The migration process has not been repeated.', 'attachments' ); ?></p>
242
+ <?php endif;
243
+
244
+ // make sure the database knows the migration has run
245
+ add_option( 'attachments_migrated', true, '', 'no' );
246
+
247
+ break;
248
+ }
249
+ }
250
+ else
251
+ { ?>
252
+ <?php if( false == get_option( 'attachments_migrated' ) && $legacy->found_posts ) : ?>
253
+ <h2><?php _e( 'Migrate legacy Attachments', 'attachments' ); ?></h2>
254
+ <p><?php _e( 'Attachments has found records from version 1.x. Would you like to migrate them to version 3?', 'attachments' ); ?></p>
255
+ <p><a href="?page=attachments&amp;migrate=1&amp;nonce=<?php echo wp_create_nonce( 'attachments-migrate-1' ); ?>" class="button-primary button"><?php _e( 'Migrate legacy Attachments', 'attachments' ); ?></a></p>
256
+ <?php elseif( true == get_option( 'attachments_migrated' ) ) : ?>
257
+ <p><?php _e( 'You have already migrated your legacy Attachments.', 'attachments' ); ?></p>
258
+ <?php endif; ?>
259
+ <h2><?php _e( 'Revert to version 1.x', 'attachments' ); ?></h2>
260
+ <p><?php _e( 'If you would like to forcefully revert to the 1.x version branch of Attachments, add the following to your', 'attachments' ); ?> <code>wp-config.php</code>:</p>
261
+ <p><code>define( 'ATTACHMENTS_LEGACY', true );</code></p>
262
+ <h2><?php _e( 'Meta box customization', 'attachments' ); ?></h2>
263
+ <p><?php _e( 'By default, Attachments implements a single meta box on Posts and Pages with two fields. You can disable this default instance by adding the following to your', 'attachments' ); ?> <code>wp-config.php</code>:</p>
264
+ <p><code>define( 'ATTACHMENTS_DEFAULT_INSTANCE', false );</code></p>
265
+ <p><?php _e( "Your Attachments meta box(es) can be customized by adding the following to your theme's", 'attachments' ); ?> <code>functions.php</code>:</p>
266
+ <script src="https://gist.github.com/4217475.js"> </script>
267
+ <h2><?php _e( 'Using Attachments data in your theme', 'attachments' ); ?></h2>
268
+ <p><?php _e( "Attachments does not directly integrate with your theme out of the box, you will need to edit your theme's template files where appropriate. You can add the following within The Loop to retrieve all Attachments data for the current post:", 'attachments' ); ?></p>
269
+ <script src="https://gist.github.com/4217483.js"> </script>
270
+ <?php }
271
+
272
+ ?>
273
+
274
+ </div>